MYSQL学习笔记(个人)(第十四天)
自学《数据库系统原理与应用》——— 黄宝贵、马春梅、禹继国 —— 清华大学出版社
衔接第十三天笔记
SQL基础编程
存储过程:
存储过程是一种命名的SQL块,是一个可完成某种功能的SQL语句集,编译后长期存储与数据库中,可反复执行,效率高。
创建存储过程:
CREATE PROCEDURE 存储过程名
([IN | OUT | INOUT] 参数名1 参数类型 1,
[IN | OUT | INOUT] 参数名2 参数类型 2,
······
[IN | OUT | INOUT] 参数名 n 参数类型n)
BEGIN
[声明部分];
<执行部分(主题程序)>;
END;
IN,OUT,INOUT表示输入参数,输出参数和输入/输出参数,类似函数的参数和返回值。声明部分是有变量、游标等等才写的,无声明既没有声明部分。
(ts!!!在SQL中,系统识别到;就会自动执行,为了写完全部代码,要先用DELIMITER把语句结束符号改掉,改成其他的如$$,在写,后面记得改回来。)
创建一个存储过程user-time,输出当前用户名和时间:
DELIMITER $$
CREATE PROCEDURE user_time()
BEGIN
SELECT CURRENT_USER AS 当前用户,CURRENT_DATE AS 当前日期;
END $$
DELIMITER ;
调用存储过程:
CALL 存储过程名 ([实参1,实参2······]);
和调用函数类似,调用上面的user-time就:
CALL user-time();
把当前日期换为时间就可以对进行数据库操作的人更精确的日志操作。
创建带参数的存储过程:
创建一个可以向Student表插入数据的存储过程 insert_student:
DELIMITER $$
CREATE PROCEDURE insert_student(
p_sno CHAR(8),
p_sname VARCHAR(30),
p_sex VARCHAR(20),
p_birth DATE
)
BEGIN
DECLARE info VARCHAR(20) DEFAULT '插入成功';
DECLARE CONTINUE HANDLER FOR 1062 SET info = '插入失败,重复数据';
INSERT INTO Student VALUES(p_sno,p_sname,p_sex,p_birth);
SELECT info;
END $$
DELIMITER ;
原始数据(纯属虚构):
调用inster_student:
CALL inster_student('20250907','小优','男','2005-10-24');
成功。
输出参数的存储过程也差不多:
DELIMITER $$
CREATE PROCEDURE search_student(
s_sno CHAR(8),
OUT s_name vARCHAR(30)
)
BEGIN
DECLARE info VARCHAR(30) DEFAULT '查找成功';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET info= '查找失败';
SELECT sname INTO s_name FROM Stduent WHERE sno=s_sno;
SELECT info;
END $$
DELIMITER ;
调用就是:
SET @ssno = '20250901';
CALL search_student(@ssno,@s_name);
SELECT @s_name;
删除存储过程:
DROP PROCEDURE [IF EXISTS] 存储过程名;
函数:
函数与存储过程相似,是完成特定功能的SQL代码集合。函数必须有函数名,可以有参数,经编译后存储在数据库中,可多次反复调用。
函数与存储过程的区别主要有以下几点。
(1)函数只可以使用输人类型的参数,但参数前不可以指定IN。
(2)函数必须通过RETURN语句返回一个值,而存储过程没有返回值。
(3)函数通常作为表达式的一部分被调用,而存储过程的调用使用的是CALL语句。
MySQL默认不允许创建函数,若要创建函数,则需要设置全局变量log_bin_trust_function creators的值为1。
SET GLOBAL log_bin_trust_function_creators = 1;
创建函数:
CREATE FUNCTION 函数名([
参数名1 参数类型1,
参数名2 参数类型 2,
······
参数名n 参数类型n])
RETURNS 数据类型
BEGIN
[声明部分];
<执行部分(主程序体)>;
RETURN 表达式;
END ;
如我要创建一个返回指定学生的平均成绩的函数get_avgs:
DELIMITER $$
CREATE FUNTION get_avgs(s_sno CHAR(8))
RETURNS FLOAT
BEGIN
RETURN (SELECT ROUND(AVG(score),2) FROM Score WHERE sno = s_sno);
END $$
DELIMITER ;
函数调用:
SELECT get_avgs(<参数名>)
删除函数:
DROP FUNCTION [IF EXISTS] 函数名;
游标:
游标可以让你一次性选择多行数据,对其进行处理。类似c++的数组,一次性把东西全装进来。
声明游标:
DECLARE 游标名 CURSOR FOR SELECT语句
打开游标:
OPEN 游标名;
提取数据:
FETCH 游标名 INTO 变量列表;
关闭游标:
CLOSE 游标名;
如:有一个学院表,指定输出某学院的学生的学号和名字:
DELIMITER $$
CREATE PROCEDURE student_ browse (V_ dno CHAR(2))
BEGIN
DECLARE founddate BOOLEAN DEFAULT TRUE;
DECLARE v_sno CHAR(2) ;
DECLARE v_sname VARCHAR(10) ;
DECLARE stu_cursor CURSOR FOR SELECT sno, sname FROM Student WHERE dno=v_dno;
DECLARE CONTINUE HANDLER FOR 1329 SET founddate= FALSE;
OPEN stu_cursor;
FETCH stu_cursor INTO v_sno,v_sname;
WHILE founddate DO
SELECT v_sno,v_sname;
FETCH stu_cursor INTO v_sno,v_sname;
END WHILE;
CLOSE stu cursor;
END$$
DELIMITER ;
触发器:
触发器是一种特殊的存储过程,以独立对象的形式存储在数据库,当发生什么事,就会触发相对于的代码,从而自动维护。
创建触发器:
CREATE TRIGGER 触发器名
BEFORE | AFTER
INSERT I DELETE | UPDATE
ON 表名
FOR ЕАCH ROW
BEGIN
<触发体:主体部分,触发操作语句>;
END;
(BEFORE | AFTER表示在操作前或后触发)
创键触发器oper_sc,当向Score表插人数据时,将操作用户和操作时间登记到日志表sc_log中。
创建日志表sc_log。
CREATE TABLE sc_log
(lid INT(10) PRIMARY KEY AUTO_ INCREMENT,
username VARCHAR(30),
opertime DATETIME );
创建触发器。
CREATE TRIGGER oper_sc
BEFORE INSERT ON Score
FOR EACH ROW
BEGIN
INSERT INTO sc_log (username, opertime) VALUES (CURRENT_USER(), NOW());
END;
(因为有用到;所以还是要改变结束符)
运行。
INSERT INTO score('07','20250907','94');
删除触发器:
DROP TRIGGER [IF ECISTS] 触发器名;
这章就结束啦,也对前面的知识有一定的复习。加油加油加油!