视图、触发器、事物、存储过程、函数、流程控制
一、视图
视图是一张虚拟表,并不是真是存在的,用户可以直接使用创建完的视图名称获取结果集,该结果集可当表使用。
1.创建视图
语法:create view 视图名称 as sql语句
注意:字段名不能重复
视图是存放至数据库当中的,且视图是为了简化查询的sql语句,但是不应该更改视图中的记录。若更改了视图中的记录,有可能会影响到原来数据库中的记录。
mysql> select * from t; +----+--------+----------+ | id | NAME | password | +----+--------+----------+ | 5 | renren | 1234 | | 10 | daben | 1 | | 11 | daben | 1 | | 12 | daben | 1 | | 13 | douqi | 123 | +----+--------+----------+
mysql> select * from t1; +----+----------+----------+ | id | name | password | +----+----------+----------+ | 1 | hello | 12 | | 2 | mysql | 1 | | 3 | concat | 1 | | 4 | sunshine | 1 | | 5 | moon | 5 | +----+----------+----------+
create view t_view as select t1.id from t1 where name='hello'; mysql> select * from t_view; +----+ | id | +----+ | 1 | +----+
mysql> select t1.name from t1 where t1.id=(select id from t_view); +-------+ | name | +-------+ | hello | +-------+
2.修改视图
mysql> alter view t_view as select * from t where t.id>1;
mysql> select * from t_view; +----+--------+----------+ | id | NAME | password | +----+--------+----------+ | 5 | renren | 1234 | | 10 | daben | 1 | | 11 | daben | 1 | | 12 | daben | 1 | | 13 | douqi | 123 | +----+--------+----------+
3.删除视图
语法:DROP VIEW 视图名称 DROP VIEW teacher_view
二、触发器
触发器是可以定制用户对表进行的 增、删、改 前后的行为,但是不包括查询
1.创建触发器
插入前 create trigger tri_before_insert_t before insert on t for each row begin ... end 插入后 create trigger tri_after_insert_t after insert on t for each row begin ... end 删除前 create trigger tri_before_delete_t before delete on t for each row begin ... end 删除后 create trigger tri_after_delete_t after delete on t for each row begin ... end 更新前 create trigger tri_before_update_t before update on t for each row begin ... end 更新后 create trigger tri_after_update_t after update on t each row begin ... end
2.简单实例
1 1 准备表 2 create table cmd( 3 id int primary key auto_increment, 4 user char(32), 5 priv char(10), 6 cmd char(64), 7 sub_time datetime, 8 success enum('yes','no') 9 ); 10 11 2 准备另一张表,用来存放插入失败的数据 12 create table errlog( 13 id int primary key auto_increment, 14 err_id int 15 ); 16 17 18 3 创建触发器 19 delimiter $$ 20 create trigger tri_after_insert_cmd after insert on cmd for each row 21 begin 22 if new.success ='no' then 23 insert into errlog(err_id) values(new.id); 24 end if; 25 end $$ 26 delimiter 27 28 4 插入数据 29 insert into cmd(user,priv,cmd,sub_time,success) values 30 ('hello','0755','ls -l /etc',NOW(),'yes'), 31 ('hello','0755','cat /etc/passwd',NOW(),'no'), 32 ('hello','0755','useradd xxx',NOW(),'no'), 33 ('hello','0755','ps aux',NOW(),'yes');
3. 删除触发器
drop trigger tri_after_insert_cmd;
四、事物(transaction)
事物可以包含一系列的sql语句,事物的执行具有原子性(包含多条sql语句---要么都执行成功,要么都执行失败)。
1 create table user( 2 id int primary key auto_increment, 3 name char(32), 4 balance int 5 ); 6 7 insert into user(name,balance) values 8 ('bao',2000), 9 ('ren',2000), 10 ('yun',2000); 11 12 原子操作 13 start transaction; 14 try: 15 update user set balance=1500 where id=1; 16 update user set balance=2200 where id=2; 17 update user set balance=2300 where id=3; 18 commit; 19 except Exception: 20 出现异常情况所有的数据就会滚回初始状态 21 rollback;
五、存储过程
存储过程中包含了一系列的sql语句,存储过程又存放于MySQL中,可通过调用它的名字来执行一堆的sql语句。
优点:
替代程序写的SQL语句,实现程序于SQL解耦;基于网络传输,直接传sql数据量大,而传名字的数据量会大大降低。
缺点:程序员拓展功能不方便
方案一: 由MySQL编写存储过程 应用程序不用负责任何事情 方案二: 由应用程序使用原生sql编写存储过程 MySQL不用负责任何事情 方案三: 由应用程序创建ORM,创建类(可视为表格),通过类来实例化得到一个对象(可视为表格中的记录) ,在其中写入原生sql MySQL不负责任何事情 执行效率: 方案一>方案二>方案三 开发效率: 方案一>方案三>方案二
1. 创建简单的存储过程(无参)
delimiter $$ 创建过程 create procedure p() begin select * from 表名; end $$ delimiter; 在MySQL中调用方法 call p; 在python中基于pymysql调用 cursor.callproc('p') 取出记录 print(cursor.fetchall())
1 create table data( 2 id int primary key auto_increment, 3 name varchar(20), 4 gender char(6), 5 email varchar(50) 6 ); 7 8 delimiter $$ 9 create procedure p() 10 begin 11 声明n仅用作传入参数使用 12 declare n int default 1; 13 while (n<50) do 14 insert into data values(n,concat('moon',n),'male',concat('moon',n,'@qq.com')) 15 这里和python语法不一样 16 set n=n+1 17 end while; 18 end $$ 19 delimiter;
2. 创建并执行存储过程(有参)
对于存储过程,可以接收参数,其参数有三类: #in 仅用于传入参数用 #out 仅用于返回值用 #inout 既可以传入又可以当作返回值
1 delimiter $$ 2 create procedure p( 3 in n int, 4 out res int 5 # inout n 6 ) 7 begin 8 select * from 表名 where id>n; 9 set res=0 10 end $$ 11 delimiter; 12 13 直接在mysql中调用执行: 14 call p(6,@x); 15 set @x=123; 16 select @x; 17 18 在python的pymysql中调用执行: 19 cursor.callproc('p',(1,234)) # 实际上是set @_p_0=1; set @_p_1=234 # 0和1分别是下标 20 print(cursor.fetchall()) 21 cursor.execute('select @_p_1;') 22 print(cursor.fetchone())
3. 删除存储过程
drop procedure proc_name;----proc_name是创建存储过程时的名字
六、函数
1.需掌握函数 date_format
create table article( id int primary key auto_increment, name char(32), sub_time datetime ); insert into article (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'); 选出xub_time字段的值,按照年月的格式来排序 select date_format(sub_time,'%Y-%m'),count(1), from article group by date_format(sub_time,'%Y-%m');
七、流程控制
1.if 条件语句
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 3; 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;
delimiter // create procedure proc_repeat() begin declare i int; set i=0; repeat select i; set i=i+1; until i>=5 end repeat; end // delimiter ;
begin declare i int default o; loop_label:loop set i=i+1; if i<8 then iterate loop_label; end if; if i>=10 then leave loop_label; endif; select i; end loop loop_label; end