SQL高级知识

一、变量

1、局部变量

变量可以在子程序(函数、存储过程、匿名块)中声明并使用,这些变量的作用范围是在BEGIN…END程序中。

赋值语法1:set

DECLARE var1, var2, var3 INT;  
SET var1 = 10, var2 = 20;  
SET var3 = var1 + var2; 
  • 1
  • 2
  • 3

赋值语法2:select into

BEGIN 
DECLARE var INT;
SELECT COUNT(ID) FROM student INTO var;
END
  • 1
  • 2
  • 3
  • 4

2、用户变量

在客户端链接到数据库实例整个过程中用户变量都是有效的。

赋值语法1:

SET @var = '变量';
//或者
SET @var := '变量';
SELECT @var '别名';
  • 1
  • 2
  • 3
  • 4

赋值语法2:

SELECT @var := NAME FROM student WHERE ID = 1;
SELECT NAME FROM student WHERE id = 1 INTO @var;
  • 1
  • 2

注意:

CREATE PROCEDURE test7 (OUT returnInt INT)
BEGIN 
DECLARE var1 INT;
SELECT COUNT(ID) FROM student INTO var1;
SET returnInt = var1;
SET @var2 = var1;
END
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面声明的两个变量var1和var2,var1是在procedure中创建的,属于局部变量,无法在procedure外获得;var2被声明为用户变量,在procedure外依然可以获取;

CALL test7(@var);
SELECT @var;//有结果
SELECT @var1;//没有结果,获取不到值
SELECT @var2;//属于用户变量,可以获取
  • 1
  • 2
  • 3
  • 4

3、系统变量

系统变量又分为全局变量与会话变量。

全局变量在MYSQL启动的时候由服务器自动将它们初始化为默认值,这些默认值可以通过更改my.ini这个文件来更改。

会话变量在每次建立一个新的连接的时候,由MYSQL来初始化。MYSQL会将当前所有全局变量的值复制一份。来做为会话变量(也就是说,如果在建立会话以后,没有手动更改过会话变量与全局变量的值,那所有这些变量的值都是一样的)。

全局变量与会话变量的区别就在于,对全局变量的修改会影响到整个服务器,但是对会话变量的修改,只会影响到当前的会话(也就是当前的数据库连接)。

查看全局变量:

SHOW GLOBAL VARIABLES;
  • 1

查看回话变量:

SHOW SESSION VARIABLES;
//或者
SHOW VARIABLES;
//未指定是输出全局变量还是会话变量的话,默认就输出会话变量。
  • 1
  • 2
  • 3
  • 4

改变系统变量:

SET SESSION wait_timeout = 28811;
SET @@SESSION.wait_timeout = 28822;
SET wait_timeout = 28833;
SHOW SESSION VARIABLES;
  • 1
  • 2
  • 3
  • 4

二、存储过程和函数

存储过程和函数是事先经过编译并存储在数据库中的一段SQL语句的集合,存储和和函数的区别在于函数必须有返回值,而存储过程没有,存储过程的参数可以使用IN、OUT、INOUT类型,而函数的参数只能是IN类型。

1、存储过程

CREATE PROCEDURE test1()
BEGIN
DECLARE var char(20);
SELECT sex FROM student WHERE NAME = '杀手' INTO var;
SELECT var;//此处select只是提供过程执行后变量预览,不参与实际执行过程。
END;
CALL test1();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

使用call来调用过程。

2、函数

CREATE FUNCTION test2() RETURNS CHAR(20)
BEGIN
DECLARE var1 CHAR(20);
DECLARE var2 CHAR(20);
SELECT NAME, SEX FROM student WHERE ID = 1 INTO var1, var2;
RETURN CONCAT(var1,var2);
END;
SELECT test2();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

使用select来调用函数。

3、参数类型

(1)IN:输入参数

CREATE FUNCTION test3(var CHAR(1)) RETURNS CHAR(9)
BEGIN 
RETURN CONCAT('hello,',var,'!');
END;
SELECT test3('杀手');
  • 1
  • 2
  • 3
  • 4
  • 5
CREATE PROCEDURE test4(IN var char(20))
BEGIN
DECLARE var2 CHAR(20);
SELECT sex FROM student WHERE NAME = var INTO var2;
SELECT var2;
END;
CALL test4('杀手');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意: 
1)procedure可以省略IN,function必须省略IN; 
2)两者的输入、输出、局部变量都不能使用varchar类型数据,只能使用char(自己试验总结,不知道对不对); 
3)方法体内只能使用select … into … 方法赋值,不能使用:=赋值(SELECT var2 := sex FROM student WHERE NAME = var语法不成立)

(2)OUT:输出参数

CREATE PROCEDURE test5(IN var1 CHAR(20),OUT var2 INT)
BEGIN 
SELECT ID FROM student WHERE NAME = var1 INTO var2;
END;
CALL test5('杀手',@temp);
SELECT @temp;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

(3)INOUT:输入输出参数(同时输入和输出)

CREATE PROCEDURE test6(INOUT var CHAR(50))
BEGIN 
SELECT CONCAT('姓名:',NAME,',性别',SEX) FROM student WHERE NAME = var INTO var;
END;
SET @temp = '杀手';
SELECT @temp;
CALL test6(@temp);
SELECT @temp;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

4、流程控制构造实例

(1)if-else

CREATE FUNCTION test7 (var INT) RETURNS CHAR(20)
BEGIN
IF var = 1 THEN RETURN '这是1!';
ELSEIF var = 2 THEN RETURN '这是2!';
ELSE RETURN '无法判断!';
END IF;
END;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(2)case

CREATE FUNCTION test8 (var INT) RETURNS CHAR(20)
BEGIN
CASE var 
WHEN 1 THEN RETURN '这是1!';
WHEN 2 THEN RETURN '这是2!';
ELSE RETURN '无法判断!';
END CASE;
END;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

(3)while

CREATE FUNCTION test9 (var INT) RETURNS CHAR(20)
BEGIN
WHILE var > 5 DO 
SET var = var - 5;
END WHILE;
RETURN var;
END;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(4)loop

CREATE FUNCTION test10 (var INT) RETURNS CHAR(20)
BEGIN
myloop:LOOP
SET var = var + 1;
IF var > 10 THEN
LEAVE myloop;
END IF;
END LOOP myloop;
RETURN var;
END;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

(5)repeat(重复执行)

CREATE FUNCTION test11 (var INT) RETURNS CHAR(20)
BEGIN
REPEAT 
SET var = var + 1;
UNTIL var > 10 END REPEAT;
RETURN var;
END;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

注意: 
1)whiles、loop、repeat都可以设置lable,mywhile:while、myloop:loop、myrepeat:repeat; 
2)while自带循环结束标识,所以不需要循环结束标识;loop。repeat需要循环结束标识leave,loop一般与leave连用,repeat一般与until连用。

(6)iterate(再次循环,只可以出现在WHILE、LOOP、 REPEAT语句内)

CREATE FUNCTION test12 (var INT) RETURNS CHAR(20)
BEGIN
mywhile:WHILE var < 10 DO 
SET var = var + 1;
IF var < 10 THEN ITERATE mywhile;
END IF;
END WHILE mywhile;
RETURN var;
END;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

while带有循环结束的条件,所以与iterate连用用处不大,不建议使用,repeat同理。

CREATE FUNCTION test13 (var INT) RETURNS CHAR(20)
BEGIN
myloop:LOOP
SET var = var + 1;
IF var < 10 THEN ITERATE myloop;
END IF;
LEAVE myloop;
END LOOP myloop;
RETURN var;
END;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

5、异常处理

在函数执行过程可以使用异常处理来使程序继续执行或者作为条件判断;

使用异常处理分为continueexit两种方式:

DECLARE CONTINUE HANDLER FOR SQLSTATE '23000'
BEGIN
SET @temp = 2;
END;
  • 1
  • 2
  • 3
  • 4
DECLARE EXIT HANDLER FOR 1062 
SET @temp = 2;
  • 1
  • 2

注意: 
1)declare condition(continue or exit) for后面可以写错误代码或者消息(sqlstate),两者是等价关系,可参考sql手册; 
2)遇到异常后选择执行sql语句可以写在begin…end中,适用多条执行语句;如果只有一条执行语句,可以不写在begin…end中,当不写begin…end时默认只执行声明异常后的一条语句。 
3)continue模式捕捉到异常程序继续向下执行,exit遇到捕捉到异常程序停止执行,但是两者的begin…end内的执行语句都会被执行。

6、光标

简单光标在存储程序和函数内被支持,必须在声明处理程序之前被声明,并且变量和条件必须在声明光标或处理程序之前被声明。

CREATE PROCEDURE test14()
BEGIN
DECLARE state INT DEFAULT 0;//状态描述,用于判断查询是否还有结果
DECLARE namevar CHAR(20);//声明局部变量存储查询出来的name值
DECLARE cur CURSOR FOR SELECT name FROM student;//声明光标
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET state = 1;//声明异常,遇到异常更改state状态值
OPEN cur;//打开光标
REPEAT
FETCH cur into namevar;//光标查询的语句赋值
IF NOT state THEN //if加数字,0代表false,其他数字代表true
INSERT INTO user (name) VALUES (namevar);//把所有student表中的name全部赋值到user表中的name。
END IF;
UNTIL state END REPEAT;
CLOSE cur;//关闭光标
END;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

7、动态执行sql(预处理)

CREATE PROCEDURE test15(var1 CHAR(100),var2 INT)
BEGIN
SET @sqlvar1 = var1;
SET @sqlvar2 = 'SELECT * FROM student WHERE id = ?';
SET @stmt = var2;
//方式1:传入sql语句和占位符的值
PREPARE prod1 FROM @sqlvar1;//解析sql语句
EXECUTE prod1 USING @stmt;//执行sql语句,占位符进行替换
DEALLOCATE PREPARE prod1;//释放解析和执行sql语句
//方式2:只传入占位符的值,sql语句在存储过程中直接写死
PREPARE prod2 FROM @sqlvar2;
EXECUTE prod2 USING @stmt;
DEALLOCATE PREPARE prod2;
END;
CALL test15('SELECT * FROM student WHERE id = ?','1');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

注意: 
动态执行sql时,只能使用用户变量,不能使用局部变量。

三、数学函数

1、round()

RAND() * 取得0 ≤ v ≤ 1.0的随机浮点数;

SELECT RAND() * ((SELECT MAX(id) FROM student) - (SELECT MIN(id) FROM student) + 1)
//取得student表中id范围内的随机浮点数
  • 1
  • 2

2、rand()

FLOOR(i + RAND() * (j – i + 1)) 取得i ≤ v ≤ j随机整数;

SELECT FLOOR((SELECT MIN(id) FROM student) + RAND() * ((SELECT MAX(id) FROM student) - (SELECT MIN(id) FROM student) + 1))
//取得student表中id范围内的随机整数
  • 1
  • 2

3、floor()

ROUND(X) 取得近似于X的整数(四舍五入);

SELECT ROUND(RAND() * ((SELECT MAX(id) FROM student) - (SELECT MIN(id) FROM student) + 1))
//取得student表中id范围内的随机整数
  • 1
  • 2

通过以上方法,如果要实现一个随机抽奖的方法,可以使用:

SELECT * FROM student AS s1 JOIN (SELECT ROUND(RAND() * ((SELECT MAX(id) FROM student) - (SELECT MIN(id) FROM student) + 1)) AS ID) AS s2 ON s1.ID >= s2.ID ORDER BY s1.ID LIMIT 1
//如果表的数据量特别大,此种方法执行效率较高
SELECT * FROM student ORDER BY RAND() LIMIT 1
//如果表的数据量小,可以使用此种方法,效率忽略不计,书写简单
  • 1
  • 2
  • 3
  • 4

四、控制流程函数

1、case then

SELECT ID,CASE STATE WHEN 1 THEN '未点评' WHEN 2 THEN '已点评' ELSE '其他' END STATE FROM composition;
//state为1时返回未点评,为2时返回已点评
  • 1
  • 2

这里写图片描述

2、if

select IF(IMAGE1 IS NULL OR IMAGE1 = '',0, 1) comType,NEW_TITLE FROM composition
//如果IMAGE1字段的值为空或是null,则输出0
  • 1
  • 2

这里写图片描述

五、字符串函数

1、concat()

SELECT CONCAT(ID,NICKNAME,SEX) FROM student;
  • 1

查询结果: 
这里写图片描述 
(这种查询如果其中一个字段为null,整体查询结果就是null)

2、CONCAT_WS()

SELECT CONCAT_WS('-',ID,NICKNAME,SEX) FROM student;
  • 1

查询结果: 
这里写图片描述 
(查询的不同字段间可以插入指定的间隔符,不存在第一种为null的情况)

3、group_concat()

SELECT t.NAME,GROUP_CONCAT(c.ID ORDER BY c.CREATE_TIME DESC SEPARATOR ';')FROM composition c,teacher t WHERE c.STATE = 3 AND t.ID = c.TID GROUP BY t.NAME
  • 1

(要求:这里有一张作文表,里面关联着相应的所属老师,老师可能对应多张作文表,现在要根据作文的状态state,来查出来每位老师所有的作文id,并按照时间顺序排列) 
这里写图片描述

4、length()

获取字符串长度

SELECT LENGTH('text');//结果为4
  • 1

5、load_file()

读取文件并将这一文件按照字符串的格式返回。 文件的位置必须在服务器上,你必须为文件制定路径全名,而且你还必须拥有FILE 特许权。文件必须可读取,文件容量必须小于 max_allowed_packet字节。

SELECT LOAD_FILE('c:/windows/my.ini ');//
  • 1

六、found_row()与row_count()

1、found_row()

返回结果与sql_calc_found_rows和limit的使用有关:

SELECT SQL_CALC_FOUND_ROWS * FROM student;
SELECT FOUND_ROWS();
//FOUND_ROWS()返回结果是所有表的行数。
  • 1
  • 2
  • 3
SELECT SQL_CALC_FOUND_ROWS * FROM student LIMIT 20;
SELECT FOUND_ROWS();
//FOUND_ROWS()返回结果是所有表的行数。
  • 1
  • 2
  • 3
SELECT * FROM student LIMIT 20;
SELECT FOUND_ROWS();
//FOUND_ROWS()返回结果是20
  • 1
  • 2
  • 3
SELECT * FROM student LIMIT 20;
SELECT FOUND_ROWS();
//FOUND_ROWS()返回结果是所有表的行数。
  • 1
  • 2
  • 3

总结,只要有sql_calc_found_rows出现,返回的结果就是表的所有行数,如果没有sql_calc_found_rows出现,返回结果与limit使用相关。

2、row_count()

与insert、update、delete联合使用时,表示插入、修改、删除的行数,单独使用只返回-1。

INSERT INTO student (name,sex) VALUES ('测试','男');
SELECT row_count();
//返回结果为1。
  • 1
  • 2
  • 3
DELETE FROM student WHERE sex = '男';
SELECT row_count();
//返回结果为性别是男的所有行数。
  • 1
  • 2
  • 3

七、小知识点

1、查询出来的时间转化为秒值(不是毫秒值)

select UNIX_TIMESTAMP(CREATE_TIME) time,NEW_TITLE FROM composition 
  • 1

2、全文搜索

alter table composition add fulltext(CONTENT);//加入索引
SELECT * FROM composition WHERE MATCH CONTENT AGAINST ('b');
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值