MySql创建函数与过程,触发器, shell脚本与sql的相互调用。
一:函数
1:创建数据库和表deptartment,
mysql> use DBSC; Database changed mysql> create table deptartment(dept_name varchar(20), -> budget bigint(20), -> building varchar(20)); Query OK, 0 rows affected mysql> insert into deptartment values('电子系',10000,'2号楼'); Query OK, 1 row affected mysql> insert into deptartment values('通信系',40000,'3号楼'); Query OK, 1 row affected mysql> insert into deptartment values('计算机系',100000,'6号楼');
2:创建表 instructor
create table instructor(id int,
salary int,
dept_name varchar(20),
foreign key(dept_name) references deptartment(dept_name)) ENGINE=innodb DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
提示错误:1005 - Can't create table 'dbsc.instructor' (errno: 150)
修改数据表deptartment 的执行引擎:
alter table deptartment engine=innodb;
依然提示错误,因为外键约束的字段必须为被应用的表的主键。 修改 deptartment 中dept_name的定义。
alter table deptartment modify dept_name varchar(20) primary key;
3:向表instructor中添加数据。
mysql> insert into instructor values(1,1000,'电子系'); Query OK, 1 row affected mysql> insert into instructor values(2,1000,'电子系'); Query OK, 1 row affected mysql> insert into instructor values(3,1000,'电子系'); Query OK, 1 row affected mysql> insert into instructor values(4,1000,'电子系'); Query OK, 1 row affected mysql> insert into instructor values(5,1000,'电子系'); Query OK, 1 row affected mysql> insert into instructor values(1,1000,'通信系'); Query OK, 1 row affected mysql> insert into instructor values(2,1000,'通信系'); Query OK, 1 row affected mysql> insert into instructor values(3,1000,'通信系'); Query OK, 1 row affected mysql> insert into instructor values(1,1000,'计算机系'); Query OK, 1 row affected
4:创建函数
创建函数提示错误: https://blog.csdn.net/topasstem8/article/details/8216740/
1418 - This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
修改
mysql> set global log_bin_trust_function_creators=TRUE;
创建有参函数: 数据库默认语句分隔符为;,DELIMITER // 将数据库语句执行分隔符改为//。
DELIMITER // create function dept_count(deptName varchar(20)) returns integer begin return( select count(*) from instructor where instructor.dept_name = deptName); end// DELIMITER ;
5:使用函数, 求出instructor中院系教师大于2的deptartment
mysql> select * from deptartment where dept_count(dept_name)>2; +-----------+--------+----------+ | dept_name | budget | building | +-----------+--------+----------+ | 电子系 | 10000 | 2号楼 | | 通信系 | 40000 | 3号楼 | +-----------+--------+----------+ 2 rows in set
https://www.cnblogs.com/taiguyiba/p/6619027.html
6: 在函数中定义变量,返回赋值后的变量。
mysql> DELIMITER // create function dept_count(deptName varchar(20)) returns integer begin declare d_count integer ; select count(*) into d_count from instructor where instructor.dept_name = deptName; return d_count; end// DELIMITER ; Query OK, 0 rows affected mysql> select dept_count('电子系'); +----------------------+ | dept_count('电子系') | +----------------------+ | 5 | +----------------------+ 1 row in set
7:创建无参函数
mysql> CREATE FUNCTION simpleFun()RETURNS VARCHAR(20) RETURN "电子系"; 1304 - FUNCTION simpleFun already exists mysql> select * from deptartment where dept_name=simpleFun(); +-----------+--------+----------+ | dept_name | budget | building | +-----------+--------+----------+ | 电子系 | 10000 | 2号楼 | +-----------+--------+----------+ 1 row in set
二:过程:使用一中的表 https://www.cnblogs.com/oskyhg/p/7679962.html
1:创建无参数的过程,查询的值直接返回。
drop procedure if exists pro1;
mysql> create procedure pro1() select 5 -> ; Query OK, 0 rows affected mysql> call pro1(); +---+ | 5 | +---+ | 5 | +---+ 1 row in set Query OK, 0 rows affected mysql>
mysql> drop procedure if exists pro1;
mysql> create procedure pro1() select * from instructor; Query OK, 0 rows affected mysql> call pro1(); +----+--------+-----------+ | id | salary | dept_name | +----+--------+-----------+ | 1 | 1000 | 电子系 | | 2 | 1000 | 电子系 | | 3 | 1000 | 电子系 | | 4 | 1000 | 电子系 | | 5 | 1000 | 电子系 | | 1 | 1000 | 通信系 | | 2 | 1000 | 通信系 | | 3 | 1000 | 通信系 | | 1 | 1000 | 计算机系 | +----+--------+-----------+ 9 rows in set Query OK, 0 rows affected mysql>
2:创建有输入输出参数的过程。 mysql中的变量 https://blog.csdn.net/qq_34531925/article/details/79483312
mysql> -- 定义执行语句的分割符,遇到//就执行。 DELIMITER // drop procedure if exists pro3 // -- in输入参数和类型,out输出参数和类型 create procedure pro3(in parm1 int, out parm2 int) begin -- 定义自定义变量,局部变量 declare parm3 int; -- 对输入参数值进行判断 if parm1=10 then set parm3=parm1; -- 对parm3进行赋值 else set parm3=20; end if; -- 插入操作,自定义变量的值做为插入值 insert into instructor(id) values(parm3); -- 查询结果赋值给输出参数 select count(*) into parm2 from instructor; end // -- 调用过程,将输出值,赋值给outValue变量 call pro3(10,@outValue) // -- 查询输出值,@outValue 是用户变量 select @outValue // Query OK, 0 rows affected Query OK, 0 rows affected Query OK, 1 row affected +-----------+ | @outValue | +-----------+ | 12 | +-----------+ 1 row in set mysql>
3:当没有输出参数时,会将过程中最后的select查询结果作为过程的结果
mysql> create procedure pro1(name varchar(20)) select * from instructor where dept_name=name;// Query OK, 0 rows affected mysql> call pro1('电子系');// +----+--------+-----------+ | id | salary | dept_name | +----+--------+-----------+ | 1 | 1000 | 电子系 | | 2 | 1000 | 电子系 | | 3 | 1000 | 电子系 | | 4 | 1000 | 电子系 | | 5 | 1000 | 电子系 | +----+--------+-----------+ 5 rows in set Query OK, 0 rows affected
三:函数和过程 支持for while语句。
创建工资表
mysql> create table salarie(name varchar(20),salary int(11)); mysql> insert into salarie values('zhangsan',2000); mysql> insert into salarie values('lisi',2500); mysql> insert into salarie values('wangwu',3000);
1:使用过程中的while语句向sql表中添加数据
mysql> delimiter // drop procedure if exists salary // create procedure salary() begin declare i int default 0; while i<10 do insert into salarie values('wangwu',100); set i=i+1; end while; end // Query OK, 0 rows affected Query OK, 0 rows affected mysql> call salary();// Query OK, 1 row affected mysql> select * from salarie; // +----------+--------+ | name | salary | +----------+--------+ | zhangsan | 2000 | | lisi | 2500 | | wangwu | 3000 | | wangwu | 100 | | wangwu | 100 | | wangwu | 100 | | wangwu | 100 | | wangwu | 100 | | wangwu | 100 | | wangwu | 100 | | wangwu | 100 | | wangwu | 100 | | wangwu | 100 | +----------+--------+ 13 rows in set
2:使用repeat语句向数据库中添加数据
delimiter // drop procedure if exists salary // create procedure salary() begin declare i int default 0; repeat insert into salarie values('lisi',100); set i=i+1; until i>5 end repeat; end //
3: 使用loop循环插入。 read_loop为起的loop名字,可以为任意名。
delimiter // drop procedure if exists StatisticStore; // CREATE PROCEDURE StatisticStore() BEGIN declare i int default 0; read_loop:loop if i>6 then leave read_loop; end if; insert into salarie values('zhangsan',300); set i=i+1; end loop; END; //
四:使用游标,对查询出来的记录进行迭代操作。 游标只能在存储过程中使用。使用三中的表 https://blog.csdn.net/liguo9860/article/details/50848216
向表中添加一个自增的字段,用于区分各个记录。
alter table `salarie` add `id` int AUTO_INCREMENT UNIQUE;//
mysql> select * from salarie; +----------+--------+----+ | name | salary | id | +----------+--------+----+ | zhangsan | 2000 | 1 | | lisi | 2500 | 2 | | wangwu | 3000 | 3 | | wangwu | 100 | 4 | | wangwu | 100 | 5 | | wangwu | 100 | 6 | | wangwu | 100 | 7 | | wangwu | 100 | 8 | | wangwu | 100 | 9 | | wangwu | 100 | 10 | | wangwu | 100 | 11 | | wangwu | 100 | 12 | | wangwu | 100 | 13 | | lisi | 100 | 14 | | lisi | 100 | 15 | | lisi | 100 | 16 | | lisi | 100 | 17 | | lisi | 100 | 18 | | lisi | 100 | 19 | | zhangsan | 300 | 20 | | zhangsan | 300 | 21 | | zhangsan | 300 | 22 | | zhangsan | 300 | 23 | | zhangsan | 300 | 24 | | zhangsan | 300 | 25 | | zhangsan | 300 | 26 | +----------+--------+----+ 26 rows in set
向工资低于2700的员工每人加一百块钱工资的工程如下,并将工资低于2700的员工的总额统计出来。
mysql> delimiter // drop procedure if exists addMoney; // CREATE PROCEDURE addMoney() BEGIN
-- 定义的游标变量,用于接收查询出来的记录 declare oldSalary int; declare nid int; declare total int default 0; declare done int default false; declare cur cursor for select salary,id from salarie where salary<2700;
-- 定义的标记符done, 直到最后将游标中的数据全部取出,设置done为true declare continue HANDLER for not found set done = true; set total = 0; open cur; read_loop:loop fetch cur into oldSalary,nid; if done then leave read_loop; end if; update salarie set salary=salary+100 where id=nid; set total = total + oldSalary; end loop; close cur; select total; END; // Query OK, 0 rows affected Query OK, 0 rows affected mysql> call addMoney;// +-------+ | total | +-------+ | 8200 | +-------+ 1 row in set Query OK, 0 rows affected mysql> select * from salarie; -> // +----------+--------+----+ | name | salary | id | +----------+--------+----+ | zhangsan | 2100 | 1 | | lisi | 2600 | 2 | | wangwu | 3000 | 3 | | wangwu | 200 | 4 | | wangwu | 200 | 5 | | wangwu | 200 | 6 | | wangwu | 200 | 7 | | wangwu | 200 | 8 | | wangwu | 200 | 9 | | wangwu | 200 | 10 | | wangwu | 200 | 11 | | wangwu | 200 | 12 | | wangwu | 200 | 13 | | lisi | 200 | 14 | | lisi | 200 | 15 | | lisi | 200 | 16 | | lisi | 200 | 17 | | lisi | 200 | 18 | | lisi | 200 | 19 | | zhangsan | 400 | 20 | | zhangsan | 400 | 21 | | zhangsan | 400 | 22 | | zhangsan | 400 | 23 | | zhangsan | 400 | 24 | | zhangsan | 400 | 25 | | zhangsan | 400 | 26 | +----------+--------+----+ 26 rows in set
五:触发器
FOR EACH ROW,可以迭代取出每一行中的列的 数据。
创建触发器,并使用。 创建插入触发器,当新加入的薪水大于1000时,减去200。
mysql> drop trigger if exists BeforeInsert; // CREATE TRIGGER BeforeInsert BEFORE insert ON salarie FOR EACH ROW BEGIN IF new.salary> 1000 THEN SET new.salary = new.salary-200; END IF; END; // Query OK, 0 rows affected Query OK, 0 rows affected mysql> insert into salarie(name,salary) values('zhaoliu',1500);// Query OK, 1 row affected mysql> select * from salarie;// +----------+--------+----+ | name | salary | id | +----------+--------+----+ | zhangsan | 2100 | 1 | | lisi | 2600 | 2 | | wangwu | 3000 | 3 | | wangwu | 200 | 4 | | wangwu | 200 | 5 | | wangwu | 200 | 6 | | wangwu | 200 | 7 | | wangwu | 200 | 8 | | wangwu | 200 | 9 | | wangwu | 200 | 10 | | wangwu | 200 | 11 | | wangwu | 200 | 12 | | wangwu | 200 | 13 | | lisi | 200 | 14 | | lisi | 200 | 15 | | lisi | 200 | 16 | | lisi | 200 | 17 | | lisi | 200 | 18 | | lisi | 200 | 19 | | zhangsan | 400 | 20 | | zhangsan | 400 | 21 | | zhangsan | 400 | 22 | | zhangsan | 400 | 23 | | zhangsan | 400 | 24 | | zhangsan | 400 | 25 | | zhangsan | 400 | 26 | | zhaoliu | 1300 | 28 | +----------+--------+----+ 27 rows in set
创建更新触发器,new 代表更新的数据,准备插入的,old代表原来的数据。
当给一个员工改变薪水时,如果改变的薪水大于4000,那么还按原来的薪水。
mysql> drop trigger if exists BeforeUpdate; // CREATE TRIGGER BeforeUpdate BEFORE update ON salarie FOR EACH ROW BEGIN IF new.salary> 4000 THEN SET new.salary = old.salary; END IF; END; // Query OK, 0 rows affected Query OK, 0 rows affected mysql> update salarie set salary=7000 where id=28;// Query OK, 0 rows affected Rows matched: 1 Changed: 0 Warnings: 0 mysql> select * from salarie;// +----------+--------+----+ | name | salary | id | +----------+--------+----+ | zhangsan | 2100 | 1 | | lisi | 2600 | 2 | | wangwu | 3000 | 3 | | wangwu | 200 | 4 | | wangwu | 200 | 5 | | wangwu | 200 | 6 | | wangwu | 200 | 7 | | wangwu | 200 | 8 | | wangwu | 200 | 9 | | wangwu | 200 | 10 | | wangwu | 200 | 11 | | wangwu | 200 | 12 | | wangwu | 200 | 13 | | lisi | 200 | 14 | | lisi | 200 | 15 | | lisi | 200 | 16 | | lisi | 200 | 17 | | lisi | 200 | 18 | | lisi | 200 | 19 | | zhangsan | 400 | 20 | | zhangsan | 400 | 21 | | zhangsan | 400 | 22 | | zhangsan | 400 | 23 | | zhangsan | 400 | 24 | | zhangsan | 400 | 25 | | zhangsan | 400 | 26 | | zhaoliu | 1300 | 28 | +----------+--------+----+ 27 rows in set
mysql中不用给新的数据或旧的数据起别名,默认为new,old
其它数据库的更新或插入:
CREATE TRIGGER TestField1_BeforeInsert BEFORE INSERT ON salarie -- 新插入的行或更新的行的别名为nrow, 相当于mysql中的new 。 例如:update salarie set salary=7000 where id=28;// referencing new row as nrow -- 数据库中原来的旧数据别名为orow,相当于mysql中的old 。例如:| zhaoliu | 1300 | 28 | referencing old row as orow FOR EACH ROW BEGIN IF nrow.salary> 1000 THEN SET nrow.salary = orow.salary-200; END IF; END;
六:递归mysql不支持with recursive 递归查询语句,只能自己写循环语句迭代 https://blog.csdn.net/wickedvalley/article/details/78925041
七:sql与shell脚本的相互调用。
window上面sql与c++的相互调用。 https://blog.csdn.net/swotcoder/article/details/18524
https://blog.csdn.net/shaoyiwenet/article/details/53256103
触发器调用shell文件,shell读取mysql中最新插入的一行,读取邮箱用户名,然后发送邮件给客户。
触发器中执行shll命令, https://zhidao.baidu.com/question/2271230050936210028.html
八: 循环中使用union
delimiter // drop procedure if exists tile;// drop table if exists tempTable;// create temporary table tempTable as select * from salarie where id<3;// create procedure tile(n int) -- set @tb:=table(id int(11),salary int(11), name varchar(20)); begin while(n>0) do set n=n-1; select * from ((select * from tempTable) union (select * from salarie where id<(10+n)))t3; end while; -- select * from tempTable; end// delimiter;
mysql> call tile(3); +----------+--------+----+ | name | salary | id | +----------+--------+----+ | zhangsan | 2100 | 1 | | lisi | 2600 | 2 | | wangwu | 3000 | 3 | | wangwu | 200 | 4 | | wangwu | 200 | 5 | | wangwu | 200 | 6 | | wangwu | 200 | 7 | | wangwu | 200 | 8 | | wangwu | 200 | 9 | | wangwu | 200 | 10 | | wangwu | 200 | 11 | +----------+--------+----+ 11 rows in set +----------+--------+----+ | name | salary | id | +----------+--------+----+ | zhangsan | 2100 | 1 | | lisi | 2600 | 2 | | wangwu | 3000 | 3 | | wangwu | 200 | 4 | | wangwu | 200 | 5 | | wangwu | 200 | 6 | | wangwu | 200 | 7 | | wangwu | 200 | 8 | | wangwu | 200 | 9 | | wangwu | 200 | 10 | +----------+--------+----+ 10 rows in set +----------+--------+----+ | name | salary | id | +----------+--------+----+ | zhangsan | 2100 | 1 | | lisi | 2600 | 2 | | wangwu | 3000 | 3 | | wangwu | 200 | 4 | | wangwu | 200 | 5 | | wangwu | 200 | 6 | | wangwu | 200 | 7 | | wangwu | 200 | 8 | | wangwu | 200 | 9 | +----------+--------+----+ 9 rows in set Query OK, 0 rows affected
九:事件 ,事件可以定时执行一些任务等。
如下:创建一个事件e1,每周执行一次过程procedure1
create event e1 on schedule every 1 week do call procedure1('hello');
mysql 误操作之后的回滚,当mysql误操作之后,又没有开启事务,可以用一下方法回滚。就是生成与误操作相反的语句。
https://www.jb51.net/article/99553.htm