SQL 变量、流程控制、函数/存储过程、事件

变量

局部变量

位于 begin … end 中,语句块执行完后即结束生命周期

  • 声明局部变量 declare var [, …] varType [defualt initVal];
    默认初始值为null,后续通过set赋值
    必须放于begin…end函数体最前面的位置
用户变量

定义在当前客户端的连接下的变量,连接断开后结束生命周期。

  • 无需声明,直接通过set赋值使用即可。
    用户变量的变量名必须以 @ 开头
    查看一个不存在的用户变量时返回null
变量赋值
  1. set赋值
SET @a = 100, @b = 200;
SET @c :=300;
SELECT @a , @b , @c;
  1. select 赋值
SELECT @c :=300;
  1. select into 赋值
    通过select语句将所查询出的字段数据依次赋值到 into 后的变量中
select num, price into  data1, data2 from test2 where num = idx;

临时表

临时表只在当前连接可见(类似用户变量),连接断开后生命周期结束

创建临时表
  • 通过CREATE TEMPORARY TABLE创建的临时表
    同一连接中重复创建,会导致报错(Table '临时表名' already exists),因此需配合if not existDROP TEMPORARY TABLE IF Exists使用
drop TEMPORARY Table IF Exists temp_table_name;
CREATE TEMPORARY TABLE IF NOT EXISTS temp_table_name AS
(
    SELECT *  FROM admit_record
);
select * from temp_table_name;
  • 通过select into创建的临时表
    MySQL不支持该语法,仅能用于变量赋值

  • 派生表
    出现在from子句的独立子查询,称为派生表。
    派生表必须具有别名,否则报错:Every derived table must have its own alias

SELECT
    COUNT(*) 
FROM
    ( SELECT DISTINCT gender FROM users ) AS user_gender;
  • 物化表
    出现在where子句的独立子查询,称为物化表。
SELECT
    * 
FROM
    users 
WHERE
    gender IN ( SELECT gender FROM users2 WHERE gender = 1 );
删除临时表

以下两种都可以删除临时表,但推荐使用后者,防止误删永久表。

DROP TABLE 临时表名;
DROP TEMPORARY TABLE 临时表名;

流程控制

if
 if condition then
        statements
    [ elseif condition then
        statements ]
    [ else
        statements ]
    end if;
case
CASE 
WHEN condition THEN statements; 
ELSE statements; 
while
[label:] while condition do
    statments
end while [label]
repeat
[label:] repeat
    statments
until condition
end repeat [label]
loop

死循环,需在过程中使用leave退出

[label:] LOOP
   statements
END LOOP [label]
leave 和 iterate

类似 break 和 continue,用于跳出循环

create
    function testLeave()
    returns varchar(255)
begin
    declare i,j int default 0;
    loop1: while (i<=5) do 
        set j = 0;
        while (j<=i) do
            if(j = 3) then
                leave loop1;
            end if;
            set j = j + 1;
        end while; 
        set i = i + 1;
    end while loop1;
    return concat('i: ', i, ' j:', j);
end;

函数与存储过程

模块化,方便复用,可在内部通过局部变量和流程控制语句实现复杂逻辑
避免了处理复杂逻辑时,数据从数据库和服务器的多次传输,所有操作都在数据库完成,提升了性能。
但因不方便调试,通常只用于数据逻辑。业务逻辑应在服务器端处理。

内置函数

SQL 拥有很多可用于计数和计算的内建函数。

  • AVG
    返回数值列的平均值。NULL 值不包括在计算中。
  • COUNT
    返回匹配指定条件的行数。通常写作count(*)count(1)。如填具体列,则返回该字段不为null的行数
  • FIRST
    返回指定的字段中第一个记录的值。
  • LAST
    返回指定的字段中最后一个记录的值。
  • MAX
    返回一列中的最大值。NULL 值不包括在计算中。
  • MIN
    返回一列中的最小值。NULL 值不包括在计算中。
  • SUM
    返回数值列的总数。
  • CONCAT 拼接
SELECT concat(admit_name,'-',admit_type) as "名称-类型",count(*) from admit_record
  • UCASE
    把字段的值转换为大写。
  • LCASE
    把字段的值转换为小写。
  • MID (LEFT,RIGHT)
    用于从文本字段中提取字符。
MID(字符串,开始位置[,截取长度,不填则到底])
LEFT(字符串,截取长度)
RIGHT(字符串,截取长度)
  • LEN
    返回文本值的长度。
  • ROUND
    用于把数值字段舍入为指定的小数位数。
SELECT ROUND(列名,小数位数) FROM table_name
  • NOW / GETDATE()
    返回当前的日期和时间。
  • FORMAT
    对字段的显示进行格式化。
SELECT FORMAT(column_name,format) FROM table_name
SELECT ProductName, UnitPrice, FORMAT(GETDATE(),'yyyy-MM-dd hh:mm:ss') as PerDate
FROM Products
  • VERSION
    当前MySQL版本
select version();
窗口函数

MySQL8开始支持窗口函数函数,只能写在 select 子句中。
函数位置支持row_number、first_value等专用窗口函数,以及sum、count、max等聚合函数:<函数>() over (partition by <用于分组的列名> order by <用于排序的列名>)
示例,输出结果按type分类并排序,且额外输出一列每个type内部按value排序的序号:

SELECT *, max(value) over ( PARTITION BY `type` ORDER BY `value` ASC ) FROM `test`;
自定义函数

通过function声明
函数体中必须通过return返回一个值。当函数体为复合结构时,需使用begin/end 语句。
和内置函数一样,可以直接在SQL语句中通过函数名()使用

 CREATE  
        [DEFINER = { user | CURRENT_USER }]
        FUNCTION functionName ( varName varType [, ... ] )
        RETURNS returnVarType
        [characteristic ...] 
        routine_body
CREATE FUNCTION hello(param int) RETURNS int
    DETERMINISTIC
BEGIN
    RETURN (select sum(advert_banner.id) from advert_banner) + param;
END;


select hello(9999)
  • characteristic 配置
    MySQL强制要求:开启bin-log后,在主服务器上,除非子程序(函数、存储过程、触发器)被声明为确定性的或者不更改数据,否则创建或者替换子程序将报错(因不确定的数据改变会导致主从服务器执行结果不同)。
    因此创建子程序时应指定特性为DETERMINISTICNO SQLREADS SQL DATA
    • NOT DETERMINISTIC 默认值,表示不确定
    • DETERMINISTIC 确定
    • NO SQL 没有SQL语句
    • CONTAINS SQL 有SQL语句
    • READS SQL DATA 只读
    • MODIFIES SQL 会改变数据
存储过程

通过procedure声明
通过call 存储过程名调用
通过INOUTINOUT定义入参和返回值

CREATE PROCEDURE 存储过程名([[IN |OUT |INOUT ] 参数名 数据类型...])`
begin
  sql语句
end;

call 存储过程名;
  • IN 输入参数:表示调用者向过程传入值(传入值可以是字面量或变量)
  • OUT 输出参数:表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)
  • INOUT 输入输出参数:既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变量)
一些注意点
  1. 替换结束符
    命令行中;作为结束符会执行语句。为了防止函数/存储过程在定义时,其过程体中的;执行语句,应使用delimiter暂时修改结束符。

  2. 删除函数/存储过程
    函数/存储过程在声明后会永久存在于数据库中,无需重复使用的函数/存储过程应在调用后通过drop删除。
    此外为防止重名问题,可在声明前先进行删除操作。此时需添加if exists避免因不存在而报错。

DELIMITER $$
DROP PROCEDURE IF EXISTS test_two $$
CREATE PROCEDURE test_two()
BEGIN
  DECLARE i INT DEFAULT 2;
  WHILE i < 17 DO
    INSERT INTO `role_permission_group`  (`role_id`, `pergroup_id`) VALUES ('1',i);
  SET i = i+1;
  end WHILE;

END$$
DELIMITER ;
CALL  test_two();
DROP PROCEDURE test_two;

事件

事件是MySQL自带的功能,用于执行定时任务。

  1. 查看已开启事件功能
SHOW VARIABLES LIKE 'event_scheduler';
SELECT @@event_scheduler;
  1. 启用事件功能
SET GLOBAL event_scheduler = ON;

并在配置文件中添加event_scheduler=ON并重启,否则mysql重启后事件重置。

  1. 编写事件
CREATE EVENT IF NOT EXISTS test123 ON SCHEDULE EVERY 3 SECOND
ON COMPLETION PRESERVE
DO INSERT INTO ceshisy(lpname) VALUES(NOW());
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容

  • 定义: 存储过程和函数是在数据库中定义一些SQL语句的集合,然后直接调用这些存储过程和函数来执行已经定义好的SQL...
    一枚豪迈的胡萝卜阅读 616评论 1 0
  • 首先,什么是存储过程?存储过程是为了完成某个数据库中的特定个功能而完成的语句集。该语句集包括SQL语句(对数据的增...
    你的操作666阅读 355评论 0 1
  • 存储过程 存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,...
    Rannio阅读 570评论 0 0
  • 当前数据库中有一张acount表 一、存储过程的创建: (1)语法:mysql> CREATE PROCEDURE...
    Help_II阅读 256评论 0 0
  • 渐变的面目拼图要我怎么拼? 我是疲乏了还是投降了? 不是不允许自己坠落, 我没有滴水不进的保护膜。 就是害怕变得面...
    闷热当乘凉阅读 4,241评论 0 13