存储过程框架
DEMILITER $$ -- 重定义符
DROP PROCEDURE IF EXISTS store_procedure$$ -- 如果存在此名的存储过程,先删除
CREATE PROCEDURE store_procedure() -- 创建名为store_procedure的存储过程
BEGIN -- 开始
-- 内容
END$$ -- 结束
DEMILITER ; -- 恢复;为分隔符
在使用复合语句时,必须考虑和解决这样一个问题:复合语句块里的语句必须以分号(;)彼此隔开,但因为分号同时也是mysql程序默认使用的语句分隔符,所以在使用mysql程序定义存储程序时会发生冲突。解决这个问题的办法是使用DELIMITER命令把mysql程序的语句分隔符重定义为另一个字符或字符串。
注释:
两个连字符加一个空格的单行注释,如:-- 注释
类似C语言的多行注释,如:/*注释
*/
变量:
变量声明:
DECLARE 变量名;
示例:DECLARE my_integer INT;
变量声明同时初始化:
DECLARE 变量名 DEFAULT 变量初始化值;
示例:DECLARE my_integer INT DEFAULT 0;
变量赋值:
SET 变量名=值;
示例:SET my_integer=1;
常用的MySQL数据类型
数据类型 | 解释 | 相应值的示例 |
INT, INTEGER | 32位整数。取值范围为-21亿到+21亿,如果是非符号数,值可以达到42亿,但这样做就不能包括负数 | 123,345 -2,000,000,000 |
BIGINT | 64位整数。取值范围为-9万亿到+9万亿或者非负的0到18万亿 | 9,000,000,000,000,000,000 -9,000,000,000,000,000,000 |
FLOAT | 32位浮点数。取值范围为1.7e38 to 1.7e38或者非负的0到3.4e38 | 0.00000000000002 17897.890790 -345.8908770 1.7e21 |
DOUBLE | 64位浮点数。取值范围接近无限(1.7e308) | 1.765e203 -1.765e100 |
DECIMAL(precision,scale) NUMERIC(precision,scale) | 定点数。存储情况取决于precision,能保存可能出现的数字范围。 NUMERIC通常用来保存重要的十进制数,例如现金 | 78979.00 -87.50 9.95 |
DATE | 日期类型,没有详述时间 | '1999-12-31' |
DATETIME | 日期和时间,时间精确到秒 | '1999-12-31 23:59:59' |
CHAR(length) | 定长字符串。值会被空白填充至制定长度,最大长度为255字节 | 'hello world ' |
VARCHAR(length) | 最大长度为64K的可变字符串 | 'Hello world' |
BLOB, TEXT | 最大64K长度,BLOB用来保存2进制数据,TEXT用来保存文本数据 | 任何能想象的内容 |
LONGBLOB, LONGTEXT | BLOB和TEXT的加长版本,存储能力达4GB | 任何能想象的内容,但比BLOB和TEXT能存放更大的长度 |
用户变量(全局变量):
可以跨存储过程使用;
DECALRE @g_variable INT DEFAULT 0;
参数:
参数类型分为输入(IN,默认)、输出(OUT)、输入输出(INOUT)三种类型;
存储函数只能用输入(IN)模式,但可以有一个返回值,对于需要返回多个值的功能,只能采用存储过程;
示例:存储过程计算平方根
DEMILITER $$
DROP PROCEDURE sqrt_store_procedure
CREATE PROCEDURE sqrt_store_procedure(IN in_num INT, OUT out_num FLOAT)
BEGIN
SET out_num=SQRT(in_num);
END$$
DEMILITER ;
操作符:
数学操作符
操作符 | 描述 | 用例 |
+ | 加 | SET var1=2+2; à 4 |
- | 减 | SET var2=3-2; à 1 |
* | 乘 | SET var3=3*2; à 6 |
/ | 除 | SET var4=10/3; à 3.3333 |
DIV | 整除 | SET var5=10 DIV à3; 3 |
% | 模 | SET var6=10%3; à 1 |
比较操作符
操作符 | 描述 | 示例 | 示例结果 |
> | 是否大于 | 1>2 | False |
< | 是否小于 | 2<1 | False |
<= | 是否小于等于 | 2<=2 | True |
>= | 是否大于等于 | 3>=2 | True |
BETWEEN | 是否位于两个值之间 | 5 BETWEEN 1 AND 10 | True |
NOT BETWEEN | 是否不位于两个值之间 | 5 NOT BETWEEN 1 AND 10 | False |
IN | 值位于列表中 | 5 IN (1,2,3,4) | False |
NOT IN | 值不位于列表中 | 5 NOT IN (1,2,3,4) | True |
= | 等于 | 2=3 | False |
<>, != | 不等于 | 2<>3 | False |
<=> | Null安全等于(如果两个值均为Null返回TRUE) | NULL<=>NULL | True |
LIKE | 匹配简单模式 | "Guy Harrison" LIKE "Guy%" | True |
REGEXP | 匹配扩展正则表达式 | "Guy Harrison" REGEXP "[Gg]reg" | False |
IS NULL | 值为空 | 0 IS NULL | False |
IS NOT NULL | 值不为空 | 0 IS NOT NULL | True |
逻辑操作符
AND操作符比较两个逻辑表达式,并且只在两个表达式都为真是才返回TRUE。
AND | TRUE | FALSE | NULL |
TRUE | TRUE | FALSE | NULL |
FALSE | FALSE | FALSE | NULL |
NULL | NULL | NULL | NULL |
OR操作符比对两个逻辑表达式,并且只要其中的一个表达式为真即返回TRUE。
OR | TRUE | FALSE | NULL |
TRUE | TRUE | TRUE | TRUE |
FALSE | TRUE | FALSE | NULL |
NULL | TRUE | NULL | NULL |
XOR操作符只有在两个值不完全为真时才返回TRUE。
XOR | TRUE | FALSE | NULL |
TRUE | FALSE | TRUE | NULL |
FALSE | TRUE | FALSE | NULL |
NULL | NULL | NULL | NULL |
位操作符
操作符 | 用途 |
| | OR |
& | AND |
<< | Shift bits to left |
>> | Shift bits to right |
~ | NOT or invert bits |
条件执行:
IF、CASE;
示例:IF
DECLARE count INT DEFAULT 0;
IF (price > 100) THEN
count = 0;
ELSEIF (prict >= 30 AND prict <= 100) THEN
count=1;
ELSE
count=2;
END IF;
示例:CASE
DECLARE count INT DEFAULT 0;
CASE enum_type
WHEN ‘A’ THEN
count=1;
WHEN ‘B’ THEN
count=2;
ELSE -- 未满足’A’、’B’的情况下,执行ELSE流程
count=3;
END CASE;
在没有ELSE的情况下,如果enum_type没有’A’、’B’的情况,会抛出一个异常:ERROR 1339 (20000): Case not found for CASE statement
CASE语句中的WHEN表达式也可以是条件,如:
CASE price
WHEN (price > 200) THEN
count=1;
WHEN ((price > 100) AND (price <= 200)) THEN
count=2;
ELSE
count=3;
END CASE;
循环:
简单循环LOOP、END LOOP;
当条件为真时,继续执行的循环WHILE、END WHILE;
循环直至条件为真:REPEAT、UNTIL;
三种循环都可以用LEAVE子句来终止循环;
示例:LOOP
DECLARE count INT DEFAULT 0;
my_loop: LOOP
SET count=count+1;
IF (count=10)
LEAVE my_loop;
END IF;
SELECT CONCAT(count, “ is select value”);
END LOOP my_loop;
SELECT “I can count to 10”;
ITERATE语句用来重新从循环头部开始执行,而不执行任何在循环中遗留下来的语句。
DECLARE count INT DEFAULT 0;
my_loop: LOOP
SET count=count+1;
IF (count=10)
LEAVE my_loop;
ELSEIF (MOD(count,2)=0)
ITERATE my_loop;
END IF;
SELECT CONCAT(count, “ is select value”);
END LOOP my_loop;
SELECT “I can count to 10 odd num”;
REPEAT……UNTIL循环,REPEAT循环的循环体总是能确保至少运行一次。
DECLARE count INT DEFAULT 0;
my_loop: REPEAT
SET count=count+1;
IF (MOD(count,2)<>0)
SELECT CONCAT(count, “ is select value”);
END IF;
UNTIL count=10
END LOOP my_loop;
SELECT “I can count to 10 odd num”;
WHILE循环,WHILE循环只有在条件为真是才执行循环。
DECLARE count INT DEFAULT 0;
my_loop: WHILE (couunt<10) DO
SET count=count+1;
IF (MOD(count,2)<>0)
SELECT CONCAT(count, “ is select value”);
END IF;
END WHILE my_loop;
SELECT “I can count to 10 odd num”;
MYSql函数:
字符串函数
这些函数主要对字符串变量执行操作,比方说:你可以连接字符串,在字符串中查找字符,得到子串和其他常规操作。
数学函数
这些函数主要对数字进行操作,比方说:你可以进行乘方(平方),三角函数(sin,cos),随机数函数和对数函数等。
日期和时间函数
折现函数主要的操作对象是日期和时间,比方说:你可以得到当前时间,从一个日期上加上或减去一个时间间隔,找出两个日期间的差异,获取某个确定的时间点(比如:得到一天中某时间的小时数)。
其它函数
这些函数包括了所有不容易被分入上面类别中函数。他们包括类型转换函数,流程控制函数(比如:CASE),信息反馈函数(比如服务器版本)和加密函数。
经常被使用的MySQL函数
函数 | 描述 |
ABS(number) | 返回提供数字的绝对值。比方说, ABS(-2.3)=2.3. |
CEILING(number) | 返回下一个最大整数,比方说, CEILING(2.3)=3. |
CONCAT(string1[,string2,string3,...]) | 返回所有提供字符串的连接形式的值 |
CURDATE | 返回当前时间(不带时间) |
DATE_ADD(date,INTERVAL amount_type) | 给提供的时间值加上一个时间间隔并返回一个新时间。正确的形式有SECOND, MINUTE, HOUR, DAY, MONTH和YEAR |
DATE_SUB(date,INTERVAL interval_type) | 从提供的时间值上减去一个时间间隔并返回一个新的时间。正确的形式有SECOND, MINUTE, HOUR, DAY, MONTH和YEAR |
FORMAT(number,decimals) | 返回一个指定精确度的数值,并给与以1000为单位的分割(通常使用“,”) |
GREATEST(num1,num2[,num3, ... ]) | 返回所有提供参数中的最大数 |
IF(test, value1,value2) | 测试一个逻辑条件,如果为真则返回value1,如果为假返回value2 |
IFNULL(value,value2) | 返回第一个值,除非第一个值为空;这样的话返回第二个值 |
INSERT(string,position,length,new) | 把一个字符串插入到另一个字符串中 |
INSTR(string,substring) | 返回一个字符串中子串的位置 |
ISNULL(expression) | 如果参数为空则返回1,否则返回0 |
LEAST(num1,num2[,num3, ... ]) | 返回参数列表中的最小值 |
LEFT(string,length) | 返回字符串最左边的部分 |
LENGTH(string) | 返回字符串中的字节数。CHAR_LENGTH可以被用来返回字符数(这会在你使用多字节字符集是产生差异) |
LOCATE(substring,string[,number]) | 返回字符串中子串的位置,可选的第三个参数为在父字符串中开始搜索的位置 |
LOWER(string) | 返回给定字符串的小写形式 |
LPAD(string,length,padding) | 返回字符串 str, 其左边由字符串padding 填补到length 字符长度,第三个参数为填充字符 |
LTRIM(string) | 删除所有字符串中的前缀空格 |
MOD(num1,num2) | 返回第一个数除于第二个数后的模(余数部分) |
NOW | 返回当前日期和时间 |
POWER(num1,num2) | 返回num1的num2次方 |
RAND([seed]) | 返回一个随机数。seed可被用于随机数生成器的种子数 |
REPEAT(string,number) | 返回一个重复number次string的字符串 |
REPLACE(string,old,new) | 用new替换所有出现old的地方 |
ROUND(number[,decimal]) | 舍去给定数值的指定精度的位数 |
RPAD(string,length,padding) | 返回字符串 str, 其右边由字符串padding 填补到length 字符长度,第三个参数为填充字符 |
RTRIM(string) | 删除字符串尾部的空格 |
SIGN(number) | 如果number小于0则返回-1,如果大于0则返回1,如果为0则返回0 |
SQRT(number) | 返回number的平方根 |
STRCMP(string1,string2) | 如果两个值相同则返回0,若根据当前分类次序,第一个参数小于第二个,则返回 -1,其它情况返回 1 。 |
SUBSTRING(string,position,length) | 从字符串指定位置开始返回length个字符 |
UPPER(string) | 将指定字符串转换为大写 |
VERSION | 返回MySQL服务器当前版本号的字符串 |
和数据库交互:
将一个SQL语句所返回的单个记录放入本地变量中;
创建一个“游标”来迭代SQL语句所返回的结果集;
执行一个SQL语句,将执行后的结果集返回给它的调用程序;
内嵌一个不返回结果集的SQL语句,如INSERT,UPDATA,DELETE等;
将一个SQL语句所返回的单个记录放入本地变量中:SELECT INTO
示例:
DECLARE num INT;
SELECT NUM(price)
INTO num
FROM tabprice;
SELECT CONCAT(“Total Price is”, num);
游标
游标的声明必须在我们所有的变量声明之后。在的变量之前定义游标会产生一个1337错误。游标总是和SELECT语句配合使用。
DECLARE cur CURSOR FOR SELECT * FROM customers;
创建一个“游标”来迭代SQL语句所返回的结果集:CURSOR
查询多条记录数据;
示例:CURSOR
DECLARE done DEFAULT -1;
DECLARE nprice DEFAULT 0;
DECLARE cur1 CURSOR FOR
SELECT price FROM tabprice;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; -- 如果没有记录,错误处理no data to fetch条件,几乎所有的游标都要用到
SET done=0;
OPEN cur1;
my_loop: LOOP
FETCH cur1 INTO nprice; -- 循环从游标中取值
IF (done=1)
LEAVE my_loop;
END IF;
END LOOP my_loop;
CLOSE cur1;
DEALLOCATE cur1; -- 释放游标
不使用no data to fetch的另一种解决方案@@FETCH_STATUS
@@fetch_status是MSSQL的一个全局变量
其值有以下三种,分别表示三种不同含义:【返回类型integer】
0 FETCH 语句成功
-1 FETCH 语句失败或此行不在结果集中
-2 被提取的行不存在
@@fetch_status值的改变是通过fetch next from实现的
“FETCH NEXT FROM Cursor”
DECLARE Employee_Cursor CURSOR FOR
SELECT LastName, FirstName FROM Northwind.dbo.Employees
OPEN Employee_Cursor
FETCH NEXT FROM Employee_Cursor
WHILE @@FETCH_STATUS = 0
BEGIN
FETCH NEXT FROM Employee_Cursor
END
CLOSE Employee_Cursor
DEALLOCATE Employee_Cursor
No data to fetch条件捕获在嵌套游标循环中使用比较复杂,有两种方案
1.在内循环结束时重置条件为0
DECLARE done DEFAULT -1;
DECLARE nprice DEFAULT 0;
DECLARE cur1 CURSOR FOR
SELECT price FROM tabprice;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; -- 如果没有记录,错误处理no data to fetch条件,几乎所有的游标都要用到
SET done=0;
OPEN cur1;
my_loop: LOOP
FETCH cur1 INTO nprice; -- 循环从游标中取值
DECLARE cur2 CURSOR FOR SELECT * FROM cumtomers;
OPEN cur2;
my_loop2: LOOP
FETCH cur2 INTO custom;
IF (done=1)
LEAVE my_loop2;
END IF;
END LOOP my_loop2;
CLOSE cur2;
DEALLOCATE cur2; -- 释放游标
SET done=0; -- 重置事件值
IF (done=1)
LEAVE my_loop;
END IF;
END LOOP my_loop;
CLOSE cur1;
DEALLOCATE cur1; -- 释放游标
2.内循环封闭为一个块
DECLARE done DEFAULT -1;
DECLARE nprice DEFAULT 0;
DECLARE cur1 CURSOR FOR
SELECT price FROM tabprice;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; -- 如果没有记录,错误处理no data to fetch条件,几乎所有的游标都要用到
SET done=0;
OPEN cur1;
my_loop: LOOP
FETCH cur1 INTO nprice; -- 循环从游标中取值
cur2begin: BEGIN
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2=1;
DECLARE cur2 CURSOR FOR SELECT * FROM cumtomers;
OPEN cur2;
my_loop2: LOOP
FETCH cur2 INTO custom;
IF (done2=1)
LEAVE my_loop2;
END IF;
END LOOP my_loop2;
CLOSE cur2;
DEALLOCATE cur2; -- 释放游标
END cur2begin;
IF (done=1)
LEAVE my_loop;
END IF;
END LOOP my_loop;
CLOSE cur1;
DEALLOCATE cur1; -- 释放游标
在存储过程中调用另一个存储过程:
CALL 存储过程名;
存储函数:
函数的参数列表中模式只能为IN。OUT和INOUT参数不被允许。制定IN关键字是被允许也是缺省的;
函数必须返回一个值,它的类型被定义于函数的头部;
函数能被SQL语句所调用;
函数可能不返回任何结果集;
在程序的真正目的是比对值和需要返回值时或者你希望在SQL语句中创建用户自定义函数的时候更多的考虑使用存储函数,而不是存储过程;
框架:
DEMILITER $$ -- 重定义符
DROP FUNCTION IF EXISTS store_function$$ -- 如果存在此名的存储函数,先删除
CREATE FUNCTION store_function() RETURNS INT DETERMINITISTIC
-- 创建名为store_procedure的存储函数
--
MySQL相较于存储过程,对于存储函数有更严格的规则。函数必须声明不修改SQL(使用NO SQL或者 READS SQL DATA子句)或者声明为DETERMINISTIC(如果服务器被允许开启二进制日志)。这个限制是为了防止当函数返回不确定值 时,数据库同步复制的不一致性,我们的样例例程使用了“deterministic”,这样我们就能确保在提供了相同的参数的情况下返回相同的值 |
BEGIN -- 开始
-- 内容
RETURN(返回值);
END$$ -- 结束
DEMILITER ; -- 恢复;为分隔符