SQL考点之存储过程、存储函数、游标

本文详细介绍了MySQL数据库中的存储过程和函数,包括它们的创建、调用、删除以及在数据处理中的应用。存储过程可以执行一系列SQL语句,支持流程控制,可用于数据统计、备份、恢复等任务。函数如自定义函数和存储函数,允许用户根据需求定制功能,如汉字转拼音、生成随机姓名等。文章通过多个实例展示了如何在实际操作中运用这些功能。
摘要由CSDN通过智能技术生成

如题:2019年10月

注:答案:if exists

前面的数据库考点比较侧重于数据库的理论,而SQL考点比较侧重于语法及使用、实现。

存储过程:

存储过程是一组具有特定功能的SQL语句集组成的可编程的函数,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数来调用执行。
存储过程是数据库管理中常用的技术之一,可以很方便的做些类似数据统计、数据分析等工作,SQL SERVER、ORACLE、MySQL都支持存储过程,但不同的数据库环境语法结构有所区别。

创建存储过程:

语法:

CREATE
    [DEFINER = { user | CURRENT_USER }]
 PROCEDURE sp_name ([proc_parameter[,...]])
    [characteristic ...]  routine_body

proc_parameter:
    [ IN | OUT | INOUT ] param_name type

characteristic:
    COMMENT 'string'
  | LANGUAGE SQL
  | [NOT] DETERMINISTIC
  | { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
  | SQL SECURITY { DEFINER | INVOKER }

routine_body:
  Valid SQL routine statement

[begin_label:] BEGIN
  [statement_list]
    
END [end_label]

IN输入参数:表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值。
OUT输出参数:该值可在存储过程内部被改变,并可返回。
INOUT输入输出参数:调用时指定,并且可被改变和返回。

1、无参数的存储过程创建
创建查找平均分最高的前三名同学的存储过程

create procedure getMax()
BEGIN
select a.sname as '姓名', AVG(b.mark) as '平均分' from 
TStudent a join TScore b on a.studentID=b.studentID
group by b.studentID order by '平均分' DESC limit 3;
END;

2、带输入参数的存储过程创建
查找指定班级的平均分最高的前三名学生

create procedure getMaxByClass(in classname VARCHAR(10))
BEGIN
select a.sname as '姓名', AVG(b.mark) as '平均分' from 
TStudent a join TScore b on a.studentID=b.studentID where a.class=classname
group by b.studentID order by '平均分' DESC limit 3;
END

3、带输入参数和输出参数的存储过程创建
根据输入的班级,找到学号最大的学生,将学号存储到输出参数。

create procedure getMaxSIDByClass(IN classname VARCHAR(20), out maxid int)
BEGIN
select MAX(studentID) into maxid from TStudent where class=classname;
END;

存储过程的调用

call sp_name[(传参)];

存储过程的删除

drop procedure [if exists] sp_name;

不能在一个存储过程中删除另一个存储过程,只能调用另一个存储过程。

存储过程名称后面必须加括号,即使存储过程没有参数传递.

存储过程信息的查看

show procedure status;

显示数据库中所有存储的存储过程基本信息,包括所属数据库,存储过程名称,创建时间等。

show create procedure sp_name;

显示某一个存储过程的详细信息。

应用例子:

使用存储过程插入数据

create procedure insertTStudent(in sid CHAR(5), name CHAR(10), ssex CHAR(1))
BEGIN
insert into TStudent (studentID, sname, sex)VALUES(sid, name, ssex);
select * from TStudent where studentID=sid;
END;
call insertTStudent('01020','孙悟空','男');

使用存储过程删除数据

根据提供的学号删除先删除学生的学生成绩,再删除学生。

create procedure deleteStudent(in sid CHAR(5))
BEGIN
delete from TScore where studentID=sid;
delete from TStudent where studentID=sid;
END;

使用存储过程备份还原数据

A、使用存储过程备份数据
创建存储过程备份学生表,根据指定的表名创建新表,将TStudent表中的记录导入到新表。

create procedure backupStudent(in tablename CHAR(10))
BEGIN
set @sql1=CONCAT('create table ',tablename,'
(
studentID VARCHAR(5),
sname VARCHAR(10),
sex CHAR(1),
cardID VARCHAR(20),
Birthday DATETIME,
email VARCHAR(20),
class VARCHAR(10),
enterTime DATETIME
)');
prepare CT1 from @sql1;
EXECUTE CT1;

set @sql2=CONCAT('insert into ', tablename, 
'(studentID,sname,sex,cardID,Birthday,email,class,enterTime)
select studentID,sname,sex,cardID,Birthday,email,class,enterTime from TStudent');
PREPARE CT2 from @sql2;
EXECUTE CT2;
END;

call backupStudent('table2019');

B、使用当前时间作为表名备份数据
创建存储过程,使用系统当前事件构造新的表名,备份Tstudent表中的记录。

create procedure backupStudentByDateTime()
BEGIN
DECLARE tablename VARCHAR(20);
set tablename = CONCAT('Table', REPLACE(REPLACE(REPLACE(now(),' ',''),':',''),'-',''));
set @sql1=CONCAT('create table ',tablename,'
(
studentID VARCHAR(5),
sname VARCHAR(10),
sex CHAR(1),
cardID VARCHAR(20),
Birthday DATETIME,
email VARCHAR(20),
class VARCHAR(10),
enterTime DATETIME
)');
prepare CT1 from @sql1;
EXECUTE CT1;

set @sql2=CONCAT('insert into ', tablename, 
'(studentID,sname,sex,cardID,Birthday,email,class,enterTime)
select studentID,sname,sex,cardID,Birthday,email,class,enterTime from TStudent');
PREPARE CT2 from @sql2;
EXECUTE CT2;
END

call backupStudentByDateTime();

C、使用存储过程还原数据
创建存储过程,根据输入的学号从指定的表还原学记录,存储过程先删除指定的学号的TStudent表中学生记录,再从指定的表中插入该学生到Tstudent表。

create procedure restoreStudent(in sid VARCHAR(5), in tablename VARCHAR(20))
BEGIN
set @sql1=concat('delete from TStudent where studentid=',sid);
prepare CT1 from @sql1;
EXECUTE CT1;
set @sql2=concat('insert into TStudent
 (Studentid,sname,sex,cardID,Birthday,Email,Class,enterTime)
  select Studentid,sname,sex,cardID,Birthday,Email,Class,enterTime
  from ',tablename,' where studentid=',sid);
prepare CT2 from @sql2;
EXECUTE CT2;
END;

修改某个学生的记录
update TStudent set sname='孙悟空' where studentID='00997';
从指定表中恢复数据
call restoreStudent('00997', 'Table20180404215950');
查看恢复的结果
select * from TStudent where studentID='00997';

实战:

增加学生到数据库表

create procedure addStudent(in num int)
begin
declare i int;
set i=1;
delete from TStudent;
while num>=i do
insert TStudent values 
(
       LPAD(convert(i,char(5)),5,'0'),
       CreateName(),
       if(ceil(rand()*10)%2=0,'男','女'),
       RPAD(convert(ceil(rand()*1000000000000000000),char(18)),18,'0'),
       Concat(convert(ceil(rand()*10)+1980,char(4)),'-',LPAD(convert(ceil(rand()*12),char(2)),2,'0'),'-',LPAD(convert(ceil(rand()*28),char(2)),2,'0')),
       Concat(PINYIN(sname),'@hotmail.com'),
       case ceil(rand()*3) when 1 then '网络与网站开发' when 2 then 'JAVA' ELSE 'NET' END,
       NOW()
);
set i=i+1;
end while;
select * from TStudent;
end

给学生添加成绩

create procedure fillScore()
begin
DECLARE St_Num INT;
DECLARE Sb_Num INT;
DECLARE i1 INT;
DECLARE i2 INT;
set i1=1;
set i2=1;
delete from TScore;
select count(*) into St_Num from TStudent;
select count(*) into Sb_Num from TSubject;
while St_Num>=i1 do
set i2=1;
while Sb_Num>=i2 do
insert TScore values
 (LPAD(convert(i1,char(5)),5,'0'),LPAD(convert(i2,char(4)),4,'0'),ceil(50+rand()*50));
set i2=i2+1;
END WHILE;
set i1=i1+1;
END WHILE;
end

存储函数:(其实就是自定义函数)

自定义函数 (user-defined function UDF)是一种对MySQL扩展的途径,其用法和内置函数相同。
自定义函数的两个必要条件:

A、参数
B、返回值(必须有)。函数可以返回任意类型的值。

创建自定义函数语法:

CREATE FUNCTION function_name(parameter_nametype,[parameter_name type,...])
RETURNS {STRING|INTEGER|REAL}
runtime_body

returns:用于指定返回值的数据类型。

runtime_body中必须包含一个return value,value用于指定返回的值。

创建带复合结构的函数体的自定义函数语法:

在函数体中,如果包含多条语句,需要把多条语句放到BEGIN...END语句块中。
 复合结构可以包括声明、循环、控制结构、游标。详见扩展:

DELIMITER //
CREATE FUNCTION function_name(parameter_nametype,[parameter_name type,...])
RETURNS {STRING|INTEGER|REAL}
BEGIN
//body
END
//      /* 此处的”//“为告诉系统函数定义结束 */

删除自定义函数:

DROP FUNCTION functionName;

自定义函数的调用:

SELECT function_name(parameter_value,...);

实例:

1、根据学生成绩判断学生成绩是否优秀

以下函数能够根据输入值范围输出成绩是否优良差。
小于60 不及格
60-69 需要努力
70-79 成绩中等
80-89 成绩优秀
90-100 成绩良好

create function getGrade(mark int)
returns VARCHAR(20)
begin
return (
       case FLOOR(mark/10) 
       when 5 then '不及格' 
       when 6 then '继续努力' 
       when 7 then '成绩良好' 
       else '成绩优秀'
       end);
END

2、汉字转拼音函数

需要先创建一张表,存储字符集GBK的代码和拼音之间对应关系。

CREATE TABLE IF NOT EXISTS `t_base_pinyin` (
  `pin_yin_` varchar(255) CHARACTER SET gbk NOT NULL,
  `code_` int(11) NOT NULL,
  PRIMARY KEY (`code_`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

插入数据:

INSERT INTO t_base_pinyin (pin_yin_,code_) VALUES ("a", 20319),("ai", 20317),("an", 20304),("ang", 20295),("ao", 20292),("ba", 20283),("bai", 20265),("ban", 20257),("bang", 20242),("bao", 20230),("bei", 20051),("ben", 20036),("beng", 20032),("bi", 20026),("bian", 20002),("biao", 19990),("bie", 19986),("bin", 19982),("bing", 19976),("bo", 19805),("bu", 19784),("ca", 19775),("cai", 19774),("can", 19763),("cang", 19756),("cao", 19751),("ce", 19746),("ceng", 19741),("cha", 19739),("chai", 19728),("chan", 19725),("chang", 19715),("chao", 19540),("che", 19531),("chen", 19525),("cheng", 19515),("chi", 19500),("chong", 19484),("chou", 19479),("chu", 19467),("chuai", 19289),("chuan", 19288),("chuang", 19281),("chui", 19275),("chun", 19270),("chuo", 19263),("ci", 19261),("cong", 19249),("cou", 19243),("cu", 19242),("cuan", 19238),("cui", 19235),("cun", 19227),("cuo", 19224),("da", 19218),("dai", 19212),("dan", 19038),("dang", 19023),("dao", 19018),("de", 19006),("deng", 19003),("di", 18996),("dian", 18977),("diao", 18961),("die", 18952),("ding", 18783),("diu", 18774),("dong", 18773),("dou", 18763),("du", 18756),("duan", 18741),("dui", 18735),("dun", 18731),("duo", 18722),("e", 18710),("en", 18697),("er", 18696),("fa", 18526),("fan", 18518),("fang", 18501),("fei", 18490),("fen", 18478),("feng", 18463),("fo", 18448),("fou", 18447),("fu", 18446),("ga", 18239),("gai", 18237),("gan", 18231),("gang", 18220),("gao", 18211),("ge", 18201),("gei", 18184),("gen", 18183),("geng", 18181),("gong", 18012),("gou", 17997),("gu", 17988),("gua", 17970),("guai", 17964),("guan", 17961),("guang", 17950),("gui", 17947),("gun", 17931),("guo", 17928),("ha", 17922),("hai", 17759),("han", 17752),("hang", 17733),("hao", 17730),("he", 17721),("hei", 17703),("hen", 17701),("heng", 17697),("hong", 17692),("hou", 17683),("hu", 17676),("hua", 17496),("huai", 17487),("huan", 17482),("huang", 17468),("hui", 17454),("hun", 17433),("huo", 17427),("ji", 17417),("jia", 17202),("jian", 17185),("jiang", 16983),("jiao", 16970),("jie", 16942),("jin", 16915),("jing", 16733),("jiong", 16708),("jiu", 16706),("ju", 16689),("juan", 16664),("jue", 16657),("jun", 16647),("ka", 16474),("kai", 16470),("kan", 16465),("kang", 16459),("kao", 16452),("ke", 16448),("ken", 16433),("keng", 16429),("kong", 16427),("kou", 16423),("ku", 16419),("kua", 16412),("kuai", 16407),("kuan", 16403),("kuang", 16401),("kui", 16393),("kun", 16220),("kuo", 16216),("la", 16212),("lai", 16205),("lan", 16202),("lang", 16187),("lao", 16180),("le", 16171),("lei", 16169),("leng", 16158),("li", 16155),("lia", 15959),("lian", 15958),("liang", 15944),("liao", 15933),("lie", 15920),("lin", 15915),("ling", 15903),("liu", 15889),("long", 15878),("lou", 15707),("lu", 15701),("lv", 15681),("luan", 15667),("lue", 15661),("lun", 15659),("luo", 15652),("ma", 15640),("mai", 15631),("man", 15625),("mang", 15454),("mao", 15448),("me", 15436),("mei", 15435),("men", 15419),("meng", 15416),("mi", 15408),("mian", 15394),("miao", 15385),("mie", 15377),("min", 15375),("ming", 15369),("miu", 15363),("mo", 15362),("mou", 15183),("mu", 15180),("na", 15165),("nai", 15158),("nan", 15153),("nang", 15150),("nao", 15149),("ne", 15144),("nei", 15143),("nen", 15141),("neng", 15140),("ni", 15139),("nian", 15128),("niang", 15121),("niao", 15119),("nie", 15117),("nin", 15110),("ning", 15109),("niu", 14941),("nong", 14937),("nu", 14933),("nv", 14930),("nuan", 14929),("nue", 14928),("nuo", 14926),("o", 14922),("ou", 14921),("pa", 14914),("pai", 14908),("pan", 14902),("pang", 14894),("pao", 14889),("pei", 14882),("pen", 14873),("peng", 14871),("pi", 14857),("pian", 14678),("piao", 14674),("pie", 14670),("pin", 14668),("ping", 14663),("po", 14654),("pu", 14645),("qi", 14630),("qia", 14594),("qian", 14429),("qiang", 14407),("qiao", 14399),("qie", 14384),("qin", 14379),("qing", 14368),("qiong", 14355),("qiu", 14353),("qu", 14345),("quan", 14170),("que", 14159),("qun", 14151),("ran", 14149),("rang", 14145),("rao", 14140),("re", 14137),("ren", 14135),("reng", 14125),("ri", 14123),("rong", 14122),("rou", 14112),("ru", 14109),("ruan", 14099),("rui", 14097),("run", 14094),("ruo", 14092),("sa", 14090),("sai", 14087),("san", 14083),("sang", 13917),("sao", 13914),("se", 13910),("sen", 13907),("seng", 13906),("sha", 13905),("shai", 13896),("shan", 13894),("shang", 13878),("shao", 13870),("she", 13859),("shen", 13847),("sheng", 13831),("shi", 13658),("shou", 13611),("shu", 13601),("shua", 13406),("shuai", 13404),("shuan", 13400),("shuang", 13398),("shui", 13395),("shun", 13391),("shuo", 13387),("si", 13383),("song", 13367),("sou", 13359),("su", 13356),("suan", 13343),("sui", 13340),("sun", 13329),("suo", 13326),("ta", 13318),("tai", 13147),("tan", 13138),("tang", 13120),("tao", 13107),("te", 13096),("teng", 13095),("ti", 13091),("tian", 13076),("tiao", 13068),("tie", 13063),("ting", 13060),("tong", 12888),("tou", 12875),("tu", 12871),("tuan", 12860) ,("tui", 12858),("tun", 12852),("tuo", 12849),("wa", 12838),("wai", 12831),("wan", 12829),("wang", 12812),("wei", 12802),("wen", 12607),("weng", 12597),("wo", 12594),("wu", 12585),("xi", 12556),("xia", 12359),("xian", 12346),("xiang", 12320),("xiao", 12300),("xie", 12120),("xin", 12099),("xing", 12089),("xiong", 12074),("xiu", 12067),("xu", 12058),("xuan", 12039),("xue", 11867),("xun", 11861),("ya", 11847),("yan", 11831),("yang", 11798),("yao", 11781),("ye", 11604),("yi", 11589),("yin", 11536),("ying", 11358),("yo", 11340),("yong", 11339),("you", 11324),("yu", 11303),("yuan", 11097),("yue", 11077),("yun", 11067),("za", 11055),("zai", 11052),("zan", 11045),("zang", 11041),("zao", 11038),("ze", 11024),("zei", 11020),("zen", 11019),("zeng", 11018),("zha", 11014),("zhai", 10838),("zhan", 10832),("zhang", 10815),("zhao", 10800),("zhe", 10790),("zhen", 10780),("zheng", 10764),("zhi", 10587),("zhong", 10544),("zhou", 10533),("zhu", 10519),("zhua", 10331),("zhuai", 10329),("zhuan", 10328),("zhuang", 10322),("zhui", 10315),("zhun", 10309),("zhuo", 10307),("zi", 10296),("zong", 10281),("zou", 10274),("zu", 10270),("zuan", 10262),("zui", 10260),("zun", 10256),("zuo", 10254);

汉字生成拼音的函数:

DROP FUNCTION IF EXISTS PINYIN;
CREATE FUNCTION PINYIN(NAME VARCHAR(255) CHARSET GBK)
RETURNS VARCHAR(255) CHARSET gbk
BEGIN
    DECLARE mycode INT;
    DECLARE tmp_lcode VARCHAR(2) CHARSET gbk;
    DECLARE lcode INT;
    DECLARE tmp_rcode VARCHAR(2) CHARSET gbk;
    DECLARE rcode INT;
    DECLARE mypy VARCHAR(255) CHARSET gbk DEFAULT '';
    DECLARE lp INT;
    SET mycode = 0;
    SET lp = 1;
    SET NAME = HEX(NAME);
    WHILE lp < LENGTH(NAME) DO
        SET tmp_lcode = SUBSTRING(NAME, lp, 2);
        SET lcode = CAST(ASCII(UNHEX(tmp_lcode)) AS UNSIGNED); 
        SET tmp_rcode = SUBSTRING(NAME, lp + 2, 2);
        SET rcode = CAST(ASCII(UNHEX(tmp_rcode)) AS UNSIGNED); 
        IF lcode > 128 THEN
            SET mycode =65536 - lcode * 256 - rcode ;
            SELECT CONCAT(mypy,pin_yin_) INTO mypy FROM t_base_pinyin WHERE CODE_ >= ABS(mycode) ORDER BY CODE_ ASC LIMIT 1;
        SET lp = lp + 4;
        ELSE
SET mypy = CONCAT(mypy,CHAR(CAST(ASCII(UNHEX(SUBSTRING(NAME, lp, 2))) AS UNSIGNED)));
            SET lp = lp + 2;
        END IF;
    END WHILE;
    RETURN LOWER(mypy);
END;

3、阿拉伯数字转汉字

create FUNCTION tohanzi (n_LowerMoney DECIMAL)
RETURNS VARCHAR(120)
BEGIN
 Declare v_LowerStr VARCHAR(200) ;
 Declare v_UpperPart VARCHAR(200) ;
 Declare v_UpperStr VARCHAR(200) ;
 Declare i_I int ;
 set v_LowerStr = LTRIM(RTRIM(ROUND(n_LowerMoney,2 ) ) ) ;
 set i_I = 1 ;
 set v_UpperStr = '' ;
 while ( i_I <=char_length(v_LowerStr ) ) do
 set v_UpperPart = CONCAT( case substring(v_LowerStr,char_length(v_LowerStr) - i_I + 1,1 )
 WHEN '.' THEN '元'
 WHEN '0' THEN '零'
 WHEN '1' THEN '壹'
 WHEN '2' THEN '贰'
 WHEN '3' THEN '叁'
 WHEN '4' THEN '肆'
 WHEN '5' THEN '伍'
 WHEN '6' THEN '陆'
 WHEN '7' THEN '柒'
 WHEN '8' THEN '捌'
 WHEN '9' THEN '玖'
 END,
 case i_I
 WHEN 1 THEN '分'
 WHEN 2 THEN '角'
 WHEN 3 THEN ''
 WHEN 4 THEN ''
 WHEN 5 THEN '拾'
 WHEN 6 THEN '佰'
 WHEN 7 THEN '仟'
 WHEN 8 THEN '万'
 WHEN 9 THEN '拾'
 WHEN 10 THEN '佰'
 WHEN 11 THEN '仟'
 WHEN 12 THEN '亿'
 WHEN 13 THEN '拾'
 WHEN 14 THEN '佰'
 WHEN 15 THEN '仟'
 WHEN 16 THEN '万'
 ELSE ''
 END );
 set v_UpperStr =CONCAT( v_UpperPart , v_UpperStr) ;
 set i_I = i_I + 1 ;
 end while;
 set v_UpperStr = REPLACE(v_UpperStr,'零拾','零') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零佰','零') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零仟','零') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零零零','零') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零零','零') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零角零分','整') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零分','整') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零角','零') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零亿零万零元','亿元') ;
 set v_UpperStr = REPLACE(v_UpperStr,'亿零万零元','亿元') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零亿零万','亿') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零万零元','万元') ;
 set v_UpperStr = REPLACE(v_UpperStr,'万零元','万元') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零亿','亿') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零万','万') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零元','元') ;
 set v_UpperStr = REPLACE(v_UpperStr,'零零','零') ;
 if ( '元' = substring(v_UpperStr,1,1)) then
 set v_UpperStr = substring(v_UpperStr,2,(char_length(v_UpperStr) - 1));
 end if;
 if ( '零' = substring(v_UpperStr,1,1)) then
 set v_UpperStr = substring(v_UpperStr,2,(char_length(v_UpperStr) - 1)) ;
 end if;
 if ( '角' = substring(v_UpperStr,1,1)) then
 set v_UpperStr = substring(v_UpperStr,2,(char_length(v_UpperStr) - 1)) ;
 end if;
 if ( '分' = substring(v_UpperStr,1,1)) then
 set v_UpperStr = substring(v_UpperStr,2,(char_length(v_UpperStr) - 1)) ;
 end if;
 if ('整' = substring(v_UpperStr,1,1)) then
 set v_UpperStr = '零元整' ;
 end if;
 return v_UpperStr;
 END

4、随机产生姓名的函数

使用三个字符串,存放用户的姓名,使用随机函数从姓名中随机排列组合成人名。

create function CreateName()
RETURNS varchar(3)
begin
DECLARE LN VARCHAR(300);
DECLARE MN VARCHAR(500);
DECLARE FN VARCHAR(500);
DECLARE LN_N INT;
DECLARE MN_N INT;
DECLARE FN_N INT;
SET LN='李王张刘陈杨黄赵周吴徐孙朱马胡郭林何高梁郑罗宋谢唐韩曹许邓萧冯曾程蔡彭潘袁于董余苏叶吕魏蒋田杜丁沈姜范江傅钟卢汪戴崔任陆廖姚方金邱夏谭韦贾邹石熊孟秦阎薛侯雷白龙段郝孔邵史毛常万顾赖武康贺严尹钱施牛洪龚';
SET MN='伟刚勇毅俊云莲真环雪荣爱妹霞香月莺媛艳瑞凡佳嘉琼勤珍贞莉桂娣叶璧才发武丽琳轮翰朗伯宏言若鸣朋斌梁栋维启克伦翔旭鹏泽晨辰士以建家致树炎德河哲江超浩璐娅琦晶裕华慧巧美婕馨影荔枝思心邦承乐绍功松善厚庆磊民友玉萍红娥玲芬芳燕彩兰凤洁梅秀娟英行时泰盛雄琛钧冠策腾楠榕风航弘峰强军平保东文辉力明永健世广志义兴良海山仁波宁贵福生龙元全国胜学祥才发武新利清飞彬富顺信子杰涛昌成康星光天达安岩中茂进林有坚和彪博诚先敬震振壮会思群豪心邦承乐绍功松善厚庆磊民友裕河哲江超浩亮政谦亨奇固之轮翰朗伯宏言若鸣朋斌梁栋维启克伦翔旭鹏泽晨辰士以建家致树炎德行时泰盛雄琛钧冠策腾楠榕风航弘';
SET FN='伟刚勇毅俊云莲真环雪荣爱妹霞香月莺媛艳瑞凡佳嘉琼勤珍贞莉桂娣叶璧才发武丽琳轮翰朗伯宏言若鸣朋斌梁栋维启克伦翔旭鹏泽晨辰士以建家致树炎德河哲江超浩璐娅琦晶裕华慧巧美婕馨影荔枝思心邦承乐绍功松善厚庆磊民友玉萍红娥玲芬芳燕彩兰凤洁梅秀娟英行时泰盛雄琛钧冠策腾楠榕风航弘峰强军平保东文辉力明永健世广志义兴良海山仁波宁贵福生龙元全国胜学祥才发武新利清飞彬富顺信子杰涛昌成康星光天达安岩中茂进林有坚和彪博诚先敬震振壮会思群豪心邦承乐绍功松善厚庆磊民友裕河哲江超浩亮政谦亨奇固之轮翰朗伯宏言若鸣朋斌梁栋维启克伦翔旭鹏泽晨辰士以建家致树炎德行时泰盛雄琛钧冠策腾楠榕风航弘';
SET LN_N=CHAR_LENGTH(LN);
SET MN_N=CHAR_LENGTH(MN);
SET FN_N=CHAR_LENGTH(FN);
return Concat(substring(LN,ceil(rand()*LN_N),1),substring(MN,ceil(rand()*MN_N),1),substring(FN,ceil(rand()*FN_N),1));
End

扩展:

1、delimiter:告诉mysql解释器,该段命令是否已经结束了,mysql是否可以执行了。 默认情况下,delimiter是分号;。在命令行客户端中,如果有一行命令以分号结束, 那么回车后,mysql将会执行该命令。但有时候,不希望MySQL这么做。在为可能输入较多的语句,且语句中包含有分号。 如试图在命令行客户端中输入如下语句 :

delimiter // 
CREATE FUNCTION `SHORTEN`(S VARCHAR(255), N INT) 
     RETURNS varchar(255) 
 BEGIN 
 IF ISNULL(S) THEN 
     RETURN ''; 
 ELSEIF N<15 THEN 
     RETURN LEFT(S, N); 
 ELSE 
     IF CHAR_LENGTH(S) <=N THEN 
    RETURN S; 
     ELSE 
    RETURN CONCAT(LEFT(S, N-10), '...', RIGHT(S, 5)); 
     END IF; 
 END IF; 
 END;// 

2、自定义局部变量

DECLARE var_name[,varname]...date_type [DEFAULT VALUE];

为变量赋值的语法:

SET parameter_name = value[,parameter_name = value...]
SELECT INTO parameter_name

如:

DECLARE x int;
SELECT COUNT(id) FROM tdb_name INTO x;
SET @x = 100;

3、流程控制语句:

自定义函数中可以使用流程控制来控制语句的执行。
MySQL中可以使用IF语句、CASE语句、LOOP语句、LEAVE语句、ITERATE语句、REPEAT语句和WHILE语句来进行流程控制。

A、IF语句
IF语句用来进行条件判断。根据是否满足条件,将执行不同的语句。其语法的基本形式如下:

IF search_condition THEN statement_list 
   [ELSEIF search_condition THEN statement_list] ... 
   [ELSE statement_list] 
END IF 

search_condition参数表示条件判断语句;statement_list参数表示不同条件的执行语句。
IF语句都需要使用END IF来结束。

例子:

IF age>20 THEN SET @count1=@count1+1;  
ELSEIF age=20 THEN SET @count2=@count2+1;  
ELSE SET @count3=@count3+1;  
END IF; 

B、CASE语句
CASE语句也用来进行条件判断,其可以实现比IF语句更复杂的条件判断。CASE语句的基本形式如下:

CASE case_value 
     WHEN when_value THEN statement_list 
     [WHEN when_value THEN statement_list] ... 
     [ELSE statement_list] 
END CASE 

case_value参数表示条件判断的变量;when_value参数表示变量的取值;
statement_list参数表示不同when_value值的执行语句。

例子:

CASE age 
WHEN 20 THEN SET @count1=@count1+1; 
ELSE SET @count2=@count2+1; 
END CASE ; 

CASE语句还有另一种形式,语法如下:

CASE 
       WHEN search_condition THEN statement_list 
       [WHEN search_condition THEN statement_list] ... 
       [ELSE statement_list] 
END CASE 

search_condition参数表示条件判断语句;statement_list参数表示不同条件的执行语句。
CASE语句实例:

CASE 
       WHEN age=20 THEN SET @count1=@count1+1; 
       ELSE SET @count2=@count2+1; 
END CASE ; 

C、LOOP语句
LOOP语句可以使某些特定的语句重复执行,实现一个简单的循环。但LOOP语句本身没有停止循环的语句,必须是遇到LEAVE语句等才能停止循环。

LOOP语句的语法的基本形式如下:

[begin_label:] LOOP 
statement_list 
END LOOP [end_label] 

begin_label参数和end_label参数分别表示循环开始和结束的标志,两个标志必须相同,而且都可以省略;statement_list参数表示需要循环执行的语句。
LOOP语句实例:

add_num: LOOP  
SET @count=@count+1;  
END LOOP add_num ; 

D、LEAVE语句
LEAVE语句主要用于跳出循环控制。其语法形式如下:

LEAVE label

label参数表示循环的标志。
LEAVE语句实例:

add_num: LOOP 
SET @count=@count+1; 
IF @count=100 THEN 
LEAVE add_num ; 
END LOOP add_num ; 

E、ITERATE语句
ITERATE语句也是用来跳出循环的语句。但是,ITERATE语句是跳出本次循环,然后直接进入下一次循环。
ITERATE语句只可以出现在LOOP、REPEAT、WHILE语句内。
ITERATE语句的基本语法形式如下:

ITERATE label

其中,label参数表示循环的标志。
ITERATE语句实例:

add_num: LOOP 
SET @count=@count+1; 
IF @count=100 THEN 
LEAVE add_num ; 
ELSE IF MOD(@count,3)=0 THEN 
ITERATE add_num; 
SELECT * FROM employee ; 
END LOOP add_num ; 

LEAVE语句是跳出整个循环,然后执行循环后面的程序。而ITERATE语句是跳出本次循环,然后进入下一次循环。
F、REPEAT语句
REPEAT语句是有条件控制的循环语句。当满足特定条件时,就会跳出循环语句。REPEAT语句的基本语法形式如下:

[begin_label:] REPEAT 
statement_list 
UNTIL search_condition 
END REPEAT [end_label] 

REPEAT循环都用END REPEAT结束。
其中,statement_list参数表示循环的执行语句;search_condition参数表示结束循环的条件,满足该条件时循环结束。

例子:

REPEAT 
SET @count=@count+1; 
UNTIL @count=100 
END REPEAT ; 

G、WHILE语句
WHILE语句也是有条件控制的循环语句。但WHILE语句和REPEAT语句是不一样的。
WHILE语句是当满足条件时,执行循环内的语句。
WHILE语句的基本语法形式如下:

[begin_label:] WHILE search_condition DO 
statement_list 
END WHILE [end_label] 

WHILE循环需要使用END WHILE来结束。
其中,search_condition参数表示循环执行的条件,满足该条件时循环执行;
statement_list参数表示循环的执行语句。例如:

WHILE @count<100 DO 
SET @count=@count+1; 
END WHILE ; 

4、游标

游标的设计是一种数据缓冲区的思想,用来存放SQL语句执行的结果。游标是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。
尽管游标能遍历结果中的所有行,但一次只指向一行。
游标的作用就是用于对查询数据库所返回的记录进行遍历,以便进行相应的操作。

游标具有三个属性:
A、不敏感(Asensitive):数据库可以选择不复制结果集
B、只读(Read only)
C、不滚动(Nonscrollable):游标只能向一个方向前进,并且不可以跳过任何一行数据。

游标的适用场景

MySQL数据库中,可以在存储过程、函数、触发器、事件中使用游标。

游标的定义

DECLARE cursor_name CURSOR FOR select_statement  

打开游标

OPEN cursor_name;

取游标中的数据

FETCH cursor_name INTO var_name [, var_name]...

关闭游标

CLOSE cursor_name;

释放游标

DEALLOCATE cursor_name

游标实例

1、创建一张游标的测试表

CREATE TABLE cursor_table
(
id INT ,
name VARCHAR(10),
age INT
)ENGINE=innoDB DEFAULT CHARSET=utf8;
insert into cursor_table values(1, '孙悟空', 500);
insert into cursor_table values(2, '猪八戒', 200);
insert into cursor_table values(3, '沙悟净', 100);
insert into cursor_table values(4, '唐僧', 20);

使用三种方式使用游标创建一个存储过程,统计年龄大于30的记录的数量。

A、Loop循环

CREATE  PROCEDURE getTotal()
BEGIN  
    DECLARE total INT; 
    ##创建接收游标数据的变量  
    DECLARE sid INT;  
    DECLARE sname VARCHAR(10);  
    #创建总数变量  
    DECLARE sage INT;  
    #创建结束标志变量  
    DECLARE done INT DEFAULT false;  
    #创建游标  
    DECLARE cur CURSOR FOR SELECT id,name,age from cursor_table where age>30;  
    #指定游标循环结束时的返回值  
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;  
    #设置初始值  
    SET sage = 0;  
    SET total=0;
    #打开游标  
    OPEN cur;  
    #开始循环游标里的数据  
    read_loop:loop  
    #根据游标当前指向的一条数据  
    FETCH cur INTO sid,sname,sage;  
    #判断游标的循环是否结束  
    IF done THEN  
        LEAVE read_loop;    #跳出游标循环  
    END IF;  
    #获取一条数据时,将count值进行累加操作,这里可以做任意你想做的操作,  
    SET total = total + 1;  
    #结束游标循环  
    END LOOP;  
    #关闭游标  
    CLOSE cur;  

    #输出结果  
    SELECT total;  
END

#调用存储过程  
call getTotal();  

B、While循环

CREATE  PROCEDURE getTotal()
BEGIN  
    DECLARE total INT; 
    ##创建接收游标数据的变量  
    DECLARE sid INT;  
    DECLARE sname VARCHAR(10);  
    #创建总数变量  
    DECLARE sage INT;  
    #创建结束标志变量  
    DECLARE done INT DEFAULT false;  
    #创建游标  
    DECLARE cur CURSOR FOR SELECT id,name,age from cursor_table where age>30;  
    #指定游标循环结束时的返回值  
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;   
    SET total = 0;  
    OPEN cur;  
    FETCH cur INTO sid, sname, sage;  
    WHILE(NOT done) 
    DO  
        SET total = total + 1;  
        FETCH cur INTO sid, sname, sage;  
    END WHILE;  

    CLOSE cur;  
    SELECT total;  
END

C、Repeat循环

CREATE getTotal()
BEGIN  
    DECLARE total INT; 
    ##创建接收游标数据的变量  
    DECLARE sid INT;  
    DECLARE sname VARCHAR(10);  
    #创建总数变量  
    DECLARE sage INT;  
    #创建结束标志变量  
    DECLARE done INT DEFAULT false;  
    #创建游标  
    DECLARE cur CURSOR FOR SELECT id,name,age from cursor_table where age > 30;  
    #指定游标循环结束时的返回值  
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = true;   
    SET total = 0;  
    OPEN cur;  
    REPEAT  
    FETCH cur INTO sid, sname, sage;   
    IF NOT done THEN  
        SET total = total + 1;  
    END IF;  
    UNTIL done END REPEAT;  
    CLOSE cur;  
    SELECT total;  
END

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guangod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值