码迷,mamicode.com
首页 > 数据库 > 详细

数据库 --- 40 视图 触发器 存储过程 事务 函数

时间:2019-01-22 23:04:55      阅读:325      评论:0      收藏:0      [点我收藏+]

标签:value   ima   网络   常量   大写   字节   begin   记录   action   

一.视图  (view)

  视图是一种虚拟表,可以把查询出来的临时表保存下来

  1.创建视图

  技术分享图片

  2.删除视图

  技术分享图片

  3.修改视图,(原始表的记录也跟着修改)

  技术分享图片

  4.查看视图

  技术分享图片

二.  触发器(trigger)可进行  增删改  操作

  1.创建触发器

  技术分享图片

   技术分享图片

 

   技术分享图片

   技术分享图片

 

   技术分享图片

   技术分享图片

  2.删除触发器

  技术分享图片

实例:

技术分享图片

技术分享图片

技术分享图片

三.存储过程

   1.  优点:

  技术分享图片

   缺点:

  技术分享图片

  2.程序与数据库结合使用的三种方式

  技术分享图片

  3.创建简单存储过程(无参)

技术分享图片

 

   4.创建存储过程(有参)

  技术分享图片

  ① in  传入参数

技术分享图片

  ② out  返回值

#查看存储过程的一些信息:show create procedure p3; #查看视图啊、触发器啊都这么看,
还可以用\G,show create procedure p3\G;\G的意思是你直接查看表结构可能横向上显示不完,
\G是让表给你竖向显示,一row是一行的字段
delimiter // create procedure p3( in n1 int, out res int ) BEGIN select * from blog where id > n1; set res = 1; #我在这里设置一个res=1,如果上面的所有sql语句全部正常执行了,
那么这一句肯定也就执行了,那么此时res=1,如果我最开始传入的时候,给res的值设置的是0,
#那么你想,最后我接收到的返回值如果是0,那么说明你中间肯定有一些sql语句执行失败了 #注意写法:out的那个参数,可以用set来设置,set设置之后表示这个res可以作为返回值,
并且不需要像python一样写一个return,你直接set之后的值,就是这个存储过程的返回值
END // delimiter ; #在mysql中调用 set @res=0; #这是MySQL中定义变量名的固定写法(set @变量名=值),可以自己规定好,
0代表假(执行失败),1代表真(执行成功),如果这个被改为1了,说明存储过程中的sql语句执行成功了
call p3(3,@res);#注意:不要这样写:call p3(3,1),这样out的参数值你写死了,
没法确定后面这个1是不是成功了,也就是说随后这个out的值可能改成0了,也就是失败了,
但是这样你就判断不了了,你后面查看的这个res就成1了,所以这个参数应该是一个变量名昂,
定义变量名就是上一句,如果你直接传一个常量数字,会报错的,写法不对。
select @res; #看一下这个结果,就知道这些sql语句是不是执行成功了,大家明白了吗~~~ #在python中基于pymysql调用,在python中只需要知道存储过程的名字就行了 cursor.callproc(p3,(3,0)) #0相当于set @res=0,为什么这里这个out参数可以写常数0啊,
因为你用的pymysql,人家会帮你搞定,pymysql其实会帮你写成这样:第一个参数变量名:@_p3_0=3,
第二个:@_p3_1=0,也就是pymysql会自动帮你对应上一个变量名,pymysql只是想让你写的时候更方便
#沿着网络将存储过程名和参数发给了mysql服务端,比咱们发一堆的sql语句肯定要快对了,mysql帮你调用存储过程 print(cursor.fetchall()) #查询select的查询结果 cursor.execute(select @_p3_0,@_p3_1;) #@_p3_0代表第一个参数,@_p3_1代表第二个参数,即返回值 print(cursor.fetchall()) #别忘了关掉: cursor.close() conn.close() #注意昂:存储过程在哪个库里面建的,就只能在哪个库里面用

  ③inout:既可传入又可以返回值:

 技术分享图片

结合事务的实例:

delimiter //
            create procedure p4(
                out status int
            )
            BEGIN
                1. 声明如果出现异常则执行{
                    set status = 1;
                    rollback;
                }       
                开始事务
                    -- 由秦兵账户减去100
                    -- 方少伟账户加90
                    -- 张根账户加10
                    commit;
                结束                
                set status = 2;              
            END //
            delimiter ;
#实现
delimiter //
create PROCEDURE p5(
    OUT p_return_code tinyint
)
BEGIN 
    DECLARE exit handler for sqlexception   #声明如果一旦出现异常则执行下面的这个begin和end里面的操作
    BEGIN 
        -- ERROR   #--是什么啊,忘了吧,是注释的意思,就告诉你后面是对错误的处理
        set p_return_code = 1;  #将out返回值改为1了,这是你自己规定的,1表示出错了
        rollback;  #回滚事务
    END; 

    DECLARE exit handler for sqlwarning  #声明了出现警告信息之后你的操作行为
    BEGIN 
        -- WARNING 
        set p_return_code = 2; 
        rollback; 
    END; 

    START TRANSACTION;  #其实咱们这个存储过程里面就是执行这个事务,
并且一直检测着这个事务,一旦出错或者出现警告,就rollback
DELETE from tb1; #事务里面的任何一条sql执行失败或者执行出现警告,
都会执行上面我们声明的那些对应的操作,如果没有任何的异常,就会自动执行下面的commit,并执行后面成功的sql
insert into blog(name,sub_time) values(yyy,now());
#拿我的代码进行测试的时候,别忘了改成你自己库里的表,还有表里面对应的字段名要有的,自己测试的时候,可以自己写一个错误的sql来试试看 COMMIT; -- SUCCESS set p_return_code = 0; #0代表执行成功 END // delimiter ; #在mysql中调用存储过程 set @res=123; call p5(@res); select @res; #在python中基于pymysql调用存储过程 cursor.callproc(p5,(123,)) #注意后面这个参数是个元祖,别忘了逗号,按照我们上面规定的,
上面有三个值0,1,2:0成功、1失败、2警告也是失败。所以我们传给这个out参数的值只要不是这三个值就行了,这里给的是100
print(cursor.fetchall()) #查询select的查询结果 cursor.execute(select @_p5_0;) print(cursor.fetchall()) #执行成功以后,查看一下结果就能看到执行后的值了

四.事务

  用于将某些操作的多个SQL作为原子性操作,

  也就是这些sql语句要么同时成功,要么都不成功,

 

create table user(
id int primary key auto_increment,
name char(32),
balance int
);

insert into user(name,balance)
values
(wsb,1000),
(chao,1000),
(ysb,1000);

#原子操作
start transaction;
update user set balance=900 where name=wsb; #买支付100元
update user set balance=1010 where name=chao; #中介拿走10元
update user set balance=1090 where name=ysb; #卖家拿到90元
commit;  #只要不进行commit操作,就没有保存下来,没有刷到硬盘上
 
#出现异常,回滚到初始状态
start transaction;
update user set balance=900 where name=wsb; #买支付100元
update user set balance=1010 where name=chao; #中介拿走10元
uppdate user set balance=1090 where name=ysb; #卖家拿到90元,出现异常没有拿到
rollback;  #如果上面三个sql语句出现了异常,就直接rollback,
数据就直接回到原来的状态了。但是执行了commit之后,rollback这个操作就没法回滚了
#我们要做的是检测这几个sql语句是否异常,没有异常直接commit,
有异常就rollback,但是现在单纯的只是开启了事务,但是还没有说如何检测异常,
我们先来一个存储过程来捕获异常,等我们学了存储过程,再细说存储过程。
commit; #通过存储过程来捕获异常:(shit!,写存储过程的是,注意每一行都不要缩进!!!
按照下面的缩进来写,居然让我翻车了!!!我记住你了~~~),我的代码直接黏贴就能用。
delimiter // create PROCEDURE p5() BEGIN DECLARE exit handler for sqlexception BEGIN rollback; END; START TRANSACTION; update user set balance=900 where name=wsb; #买支付100元 update user set balance=1010 where name=chao; #中介拿走10元 #update user2 set balance=1090 where name=‘ysb‘; #卖家拿到90元 update user set balance=1090 where name=ysb; #卖家拿到90元 COMMIT; END // delimiter ; mysql> select * from user; +----+------+---------+ | id | name | balance | +----+------+---------+ | 1 | wsb | 1000 | | 2 | chao | 1000 | | 3 | ysb | 1000 | +----+------+---------+ rows in set (0.00 sec)

 

 五.函数

  1.常用函数

一、数学函数
    ROUND(x,y)
        返回参数x的四舍五入的有y位小数的值
        
    RAND()
        返回0到1内的随机值,可以通过提供一个参数(种子)使RAND()随机数生成器生成一个指定的值。

二、聚合函数(常用于GROUP BY从句的SELECT查询中)
    AVG(col)返回指定列的平均值
    COUNT(col)返回指定列中非NULL值的个数
    MIN(col)返回指定列的最小值
    MAX(col)返回指定列的最大值
    SUM(col)返回指定列的所有值之和
    GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果    
    
三、字符串函数

    CHAR_LENGTH(str)
        返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。
    CONCAT(str1,str2,...)
        字符串拼接
        如有任何一个参数为NULL ,则返回值为 NULL。
    CONCAT_WS(separator,str1,str2,...)
        字符串拼接(自定义连接符)
        CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。

    CONV(N,from_base,to_base)
        进制转换
        例如:
            SELECT CONV(a,16,2); 表示将 a 由16进制转换为2进制字符串表示

    FORMAT(X,D)
        将数字X 的格式写为#,###,###.##,以四舍五入的方式保留小数点后 D 位, 
      并将结果以字符串的形式返回。若 D 为 0, 则返回结果不带有小数点,或不含小数部分。 例如: SELECT FORMAT(
12332.1,4); 结果为: 12,332.1000 INSERT(str,pos,len,newstr) 在str的指定位置插入字符串 pos:要替换位置其实位置 len:替换的长度 newstr:新字符串 特别的: 如果pos超过原字符串长度,则返回原字符串 如果len超过原字符串长度,则由新字符串完全替换 INSTR(str,substr) 返回字符串 str 中子字符串的第一个出现位置。 LEFT(str,len) 返回字符串str 从开始的len位置的子序列字符。 LOWER(str) 变小写 UPPER(str) 变大写 REVERSE(str) 返回字符串 str ,顺序和字符顺序相反。 SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len) 不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。
      带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。
       使用 FROM的格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,
      而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。 mysql
> SELECT SUBSTRING(Quadratically,5); -> ratically mysql> SELECT SUBSTRING(foobarbar FROM 4); -> barbar mysql> SELECT SUBSTRING(Quadratically,5,6); -> ratica mysql> SELECT SUBSTRING(Sakila, -3); -> ila mysql> SELECT SUBSTRING(Sakila, -5, 3); -> aki mysql> SELECT SUBSTRING(Sakila FROM -4 FOR 2); -> ki 四、日期和时间函数 CURDATE()或CURRENT_DATE() 返回当前的日期 CURTIME()或CURRENT_TIME() 返回当前的时间 DAYOFWEEK(date) 返回date所代表的一星期中的第几天(1~7) DAYOFMONTH(date) 返回date是一个月的第几天(1~31) DAYOFYEAR(date) 返回date是一年的第几天(1~366) DAYNAME(date) 返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE); FROM_UNIXTIME(ts,fmt) 根据指定的fmt格式,格式化UNIX时间戳ts HOUR(time) 返回time的小时值(0~23) MINUTE(time) 返回time的分钟值(0~59) MONTH(date) 返回date的月份值(1~12) MONTHNAME(date) 返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE); NOW() 返回当前的日期和时间 QUARTER(date) 返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE); WEEK(date) 返回日期date为一年中第几周(0~53) YEAR(date) 返回日期date的年份(1000~9999) 重点: DATE_FORMAT(date,format) 根据format字符串格式化date值 mysql> SELECT DATE_FORMAT(2009-10-04 22:23:00, %W %M %Y); -> Sunday October 2009 mysql> SELECT DATE_FORMAT(2007-10-04 22:23:00, %H:%i:%s); -> 22:23:00 mysql> SELECT DATE_FORMAT(1900-10-04 22:23:00, -> %D %y %a %d %m %b %j); -> 4th 00 Thu 04 10 Oct 277 mysql> SELECT DATE_FORMAT(1997-10-04 22:23:00, -> %H %k %I %r %T %S %w); -> 22 22 10 10:23:00 PM 22:23:00 00 6 mysql> SELECT DATE_FORMAT(1999-01-01, %X %V); -> 1998 52 mysql> SELECT DATE_FORMAT(2006-06-00, %d); -> 00 五、加密函数 MD5() 计算字符串str的MD5校验和 PASSWORD(str) 返回字符串str的加密版本,这个加密过程是不可逆转的,和UNIX密码加密过程使用不同的算法。 六、控制流函数 CASE WHEN[test1] THEN [result1]...ELSE [default] END 如果testN是真,则返回resultN,否则返回default CASE [test] WHEN[val1] THEN [result]...ELSE [default]END 如果test和valN相等,则返回resultN,否则返回default IF(test,t,f) 如果test是真,返回t;否则返回f IFNULL(arg1,arg2) 如果arg1不是空,返回arg1,否则返回arg2 NULLIF(arg1,arg2) 如果arg1=arg2返回NULL;否则返回arg1 七、控制流函数小练习 #7.1、准备表,将下面这些内容保存为一个.txt文件或者.sql,然后通过navicat的运行sql文件的功能导入到数据库中,还记得吗? /* Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Version : 50720 Source Host : localhost:3306 Source Database : student Target Server Type : MYSQL Target Server Version : 50720 File Encoding : 65001 Date: 2018-01-02 12:05:30 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for course -- ---------------------------- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `c_id` int(11) NOT NULL, `c_name` varchar(255) DEFAULT NULL, `t_id` int(11) DEFAULT NULL, PRIMARY KEY (`c_id`), KEY `t_id` (`t_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of course -- ---------------------------- INSERT INTO `course` VALUES (1, python, 1); INSERT INTO `course` VALUES (2, java, 2); INSERT INTO `course` VALUES (3, linux, 3); INSERT INTO `course` VALUES (4, web, 2); -- ---------------------------- -- Table structure for score -- ---------------------------- DROP TABLE IF EXISTS `score`; CREATE TABLE `score` ( `id` int(11) NOT NULL AUTO_INCREMENT, `s_id` int(10) DEFAULT NULL, `c_id` int(11) DEFAULT NULL, `num` double DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of score -- ---------------------------- INSERT INTO `score` VALUES (1, 1, 1, 79); INSERT INTO `score` VALUES (2, 1, 2, 78); INSERT INTO `score` VALUES (3, 1, 3, 35); INSERT INTO `score` VALUES (4, 2, 2, 32); INSERT INTO `score` VALUES (5, 3, 1, 66); INSERT INTO `score` VALUES (6, 4, 2, 77); INSERT INTO `score` VALUES (7, 4, 1, 68); INSERT INTO `score` VALUES (8, 5, 1, 66); INSERT INTO `score` VALUES (9, 2, 1, 69); INSERT INTO `score` VALUES (10, 4, 4, 75); INSERT INTO `score` VALUES (11, 5, 4, 66.7); -- ---------------------------- -- Table structure for student -- ---------------------------- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `s_id` varchar(20) NOT NULL, `s_name` varchar(255) DEFAULT NULL, `s_age` int(10) DEFAULT NULL, `s_sex` char(1) DEFAULT NULL, PRIMARY KEY (`s_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of student -- ---------------------------- INSERT INTO `student` VALUES (1, 鲁班, 12, ); INSERT INTO `student` VALUES (2, 貂蝉, 20, ); INSERT INTO `student` VALUES (3, 刘备, 35, ); INSERT INTO `student` VALUES (4, 关羽, 34, ); INSERT INTO `student` VALUES (5, 张飞, 33, ); -- ---------------------------- -- Table structure for teacher -- ---------------------------- DROP TABLE IF EXISTS `teacher`; CREATE TABLE `teacher` ( `t_id` int(10) NOT NULL, `t_name` varchar(50) DEFAULT NULL, PRIMARY KEY (`t_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of teacher -- ---------------------------- INSERT INTO `teacher` VALUES (1, 大王); INSERT INTO `teacher` VALUES (2, alex); INSERT INTO `teacher` VALUES (3, chao); INSERT INTO `teacher` VALUES (4, peiqi); #7.2、统计各科各分数段人数.显示格式:课程ID,课程名称,[100-85],[85-70],[70-60],[ <60] select score.c_id, course.c_name, sum(CASE WHEN num BETWEEN 85 and 100 THEN 1 ELSE 0 END) as [100-85], sum(CASE WHEN num BETWEEN 70 and 85 THEN 1 ELSE 0 END) as [85-70], sum(CASE WHEN num BETWEEN 60 and 70 THEN 1 ELSE 0 END) as [70-60], sum(CASE WHEN num < 60 THEN 1 ELSE 0 END) as [ <60] from score,course where score.c_id=course.c_id GROUP BY score.c_id;

 

   2.需要掌握的函数:date_format 

 

#1 基本使用
mysql> SELECT DATE_FORMAT(2009-10-04 22:23:00, %W %M %Y);
        -> Sunday October 2009
mysql> SELECT DATE_FORMAT(2007-10-04 22:23:00, %H:%i:%s);
        -> 22:23:00
mysql> SELECT DATE_FORMAT(1900-10-04 22:23:00,
    ->                 %D %y %a %d %m %b %j);
        -> 4th 00 Thu 04 10 Oct 277
mysql> SELECT DATE_FORMAT(1997-10-04 22:23:00,
    ->                 %H %k %I %r %T %S %w);
        -> 22 22 10 10:23:00 PM 22:23:00 00 6
mysql> SELECT DATE_FORMAT(1999-01-01, %X %V);
        -> 1998 52
mysql> SELECT DATE_FORMAT(2006-06-00, %d);
        -> 00


#2 准备表和记录
CREATE TABLE blog (
    id INT PRIMARY KEY auto_increment,
    NAME CHAR (32),
    sub_time datetime
);

INSERT INTO blog (NAME, sub_time)
VALUES
    (第1篇,2015-03-01 11:31:21),
    (第2篇,2015-03-11 16:31:21),
    (第3篇,2016-07-01 10:21:31),
    (第4篇,2016-07-22 09:23:21),
    (第5篇,2016-07-23 10:11:11),
    (第6篇,2016-07-25 11:21:31),
    (第7篇,2017-03-01 15:33:21),
    (第8篇,2017-03-01 17:32:21),
    (第9篇,2017-03-01 18:31:21);

#3. 提取sub_time字段的值,按照格式后的结果即"年月"来分组,统计一下每年每月的博客数量,
怎么写呢,按照sub_time分组,但是我们的sub_time是年月日加时间,我想看每年每月,
直接按照sub_time来分组是不行的,每篇博客的发表时间基本都是不同的,所以我们需要通过这个date_format来搞了
SELECT DATE_FORMAT(sub_time,%Y-%m),COUNT(1) FROM blog GROUP BY DATE_FORMAT(sub_time,%Y-%m); #结果 +-------------------------------+----------+ | DATE_FORMAT(sub_time,%Y-%m) | COUNT(1) | +-------------------------------+----------+ | 2015-03 | 2 | | 2016-07 | 4 | | 2017-03 | 3 | +-------------------------------+----------+ rows in set (0.00 sec)

 

   3.自定义函数

  ①创建函数

delimiter //
create function f1(
    i1 int,
    i2 int)
returns int
BEGIN
    declare num int;
    set num = i1 + i2;
    return(num);
END //
delimiter ;
delimiter //
create function f5(
    i int
)
returns int
begin
    declare res int default 0;
    if i = 10 then
        set res=100;
    elseif i = 20 then
        set res=200;
    elseif i = 30 then
        set res=300;
    else
        set res=400;
    end if;
    return res;
end //
delimiter ;

  ②删除函数

  技术分享图片

  ③执行函数

  技术分享图片

 

六. 关于查看存储过程,函数,视图,触发器的语法:

查询数据库中的存储过程和函数

       select name from mysql.proc where db = xx and type = PROCEDURE   //查看xx库里面的存储过程
       select name from mysql.proc where db = xx and type = FUNCTION   //函数

       show procedure status; //存储过程
       show function status;     //函数

查看存储过程或函数的创建代码

  show create procedure proc_name;
  show create function func_name;

查看视图
  SELECT * from information_schema.VIEWS   //视图
  SELECT * from information_schema.TABLES   //表

查看触发器
  SHOW TRIGGERS [FROM db_name] [LIKE expr]
  SELECT * FROM triggers T WHERE trigger_name=”mytrigger” \G;其中triggers T就是triggers as T的意思,起别名

 

 七.流程控制

  1.条件语句

delimiter //
CREATE PROCEDURE proc_if ()
BEGIN
    
    declare i int default 0;
    if i = 1 THEN
        SELECT 1;
    ELSEIF i = 2 THEN
        SELECT 2;
    ELSE
        SELECT 7;
    END IF;

END //
delimiter ;

 

   2.循环语句

delimiter //
CREATE PROCEDURE proc_while ()
BEGIN

    DECLARE num INT ;
    SET num = 0 ;
    WHILE num < 10 DO
        SELECT
            num ;
        SET num = num + 1 ;
    END WHILE ;

END //
delimiter ;

 

数据库 --- 40 视图 触发器 存储过程 事务 函数

标签:value   ima   网络   常量   大写   字节   begin   记录   action   

原文地址:https://www.cnblogs.com/sc-1067178406/p/10306370.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!