一 介绍
存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql。到目前为止,我们上面学的视图、触发器、事务等为我们简化了应用程序级别写sql语句的复杂程度,让我们在应用程序里面写sql更简单方便了,但是我们在应用程序上还是需要自己写sql的,而我们下面要学的存储过程,它是想让我们的应用程序不需要再写sql语句了,所有的sql语句,全部放到mysql里面,被mysql封装成存储过程,说白了它就是一个功能,这个功能对应着一大堆的sql语句,这些语句里面可以包括我们前面学的视图啊、触发器啊、事务啊、等等的内容,也就是说存储过程其实是什么?是一堆sql的集合体,可以直接用mysql里面提供的一堆功能,有了存储过程以后,它的好处是我项目逻辑中需要的各种查询都可以让DBA或者你自己封装到存储过程里面,以后使用的时候直接调用存储过程名就可以了,在开发应用的时候就简单了,就不要应用程序员进行sql语句的开发了,但是你想如果你真的这么做了,确实很有好处,简单很多,应用程序的开发和数据库sql语句的开发,完全的解耦了,这样,专门的人做专门的事情,专门招一个应用开发的人开发应用程序,招一个开发型DBA,会sql的开发,他把sql写完之后,封装成一个个的存储过程,给应用程序员用就行了,对不对,这个DBA就不单纯的是管理数据库系统了,还需要会写sql语句,那这样你的应用程序开发的效率就高了,运行效率也提高了,你开发应用程序的时候如果写了一堆的sql语句,这些语句是不是要通过网络传输,传输到mysql服务端来执行,然后将结果返回给你的应用程序,那么在传输的时候,你说好多的sql语句和简单的一个存储过程的名字,哪个传输的速度快,哪个发送给服务端的速度快,当然是单纯的一个存储过程的名字更快。
所以摆在你面前有两种开发模式:
第一种是招一个会开发应用程序的并且这个人还要会sql开发,这样的人既写应用程序,还写sql语句,这种情况你可以招两个人,一个是前面说的,还有一个是数据库管理人员,单纯只会管理数据库的而不会sql开发的人,这样好招人,工资也不高。(应用程序员-->只需要开发应用程序的逻辑 。 sql开发人员-->编写存储过程)
第二种:招一个应用程序开发的,只需要会应用程序级别的开发,再招一个会sql开发的DBA。(应用程序员-->开发应用+写原生sql 。 数据库人员负责维护数据库的正常运行)
我们比较一下这两种的开发模式:第二种:解耦和,开发效率高,运行效率也高,所以以后最好采用第一种开发模式,哈哈,是不是神反转,原因是什么呢,钱只是一个方面,主要还是因为以后如果你想扩展,那就很不方便了,为什么呢,因为通常sql开发人员,不如你的应用程序员更懂你的业务逻辑,一旦你要扩展一个功能,还需要跨部门沟通,导致这种工作方式受限的不只是技术层面了,这种方式在技术层面肯定是效率高的,但是要考虑人为因素,还有成本方面的考虑,所以通常咱们以后做开发,不要想着会有人给你写sql,需要你自己写的很熟练。这样,你一个部门就能搞定这两件事情。
第二种方式其实也比较麻烦,你开发程序员自己需要写sql,并且写出来的sql还存在效率问题,那么有没有一种方式可以不让开发程序员自己再写sql了,搞一个封装程度更高的东西让你来调用,有没有这种方式呢?有,就是第三种方式
第三种:应用程序除了开发应用程序的逻辑,不需要编写原生sql,只需要使用别人写好的框架,基于框架来处理数据,框架提供的功能是ORM:对象关系映射,和对象有关系,就是在应用程序里面,只需要定义一堆的类,每个类对应数据库里面的一张表,这个类一实例化,也就是一个类对象对应表里面的一条记录,得到对象以后,这个对象除了有数据之外,还有处理该条信息的方法,增删改查都有了,全都封装成了对象的一个一个的方法了,意味着你以后再想进行查询,就没必要写原生sql了,直接基于面向对象的思想来处理类与对象就行了,但是这种方式本质上还是使用了原生sql,只不过对于应用程序员来说,你不用直接写sql了,别人写好的ORM框架就帮你处理这件事儿了,帮你把你调用的那些接口方法和你传入的参数等等帮你转换为了原生sql,然后再往mysql里面提交。所以这种方式和第二种方式有些类似,但是比第二种方式要好(前提是第二种方式应用程序员的sql水平比较low的情况下,一般会比较low):
这种方式的优点:应用程序员不需要再写原生的sql了,这意味着开发效率比第二种要高,同时还兼顾了第二种方式扩展性高的好处,因为本质上还是原生sql
缺点是:执行效率还不如第二种方式高,因为你现在再想运行需要做什么事 情,首先你想,你程序里面用的是别人写好的ORM框架或者模块,你的sql要想执行,你需要做什么事儿,你的ORM框架需要把类或者类对象先翻译成原生的sql,再沿着网络发到mysql服务端,中间对了一个转换的过程,所以执行效率其实连方式二都比不上。
#方式一:
MySQL:存储过程
程序:调用存储过程#方式二:
MySQL:
程序:纯SQL语句#方式三:
MySQL:
程序:类和对象,即ORM(本质还是纯SQL语句)
delimiter //create procedure p1()
BEGIN
select* fromblog;
INSERT into blog(name,sub_time) values("xxx",now());
END//delimiter ;#在mysql中调用
call p1(); #类似于MySQL的函数,但不是函数昂,别搞混了,MySQL的函数(count()\max()\min()等等)都是放在sql语句里面用的,不能单独的使用,存储过程是可以直接调用的 call 名字+括号;#MySQL的视图啊触发器啊if判断啊等等都能在存储过程里面写,这是一大堆的sql的集合体,都可以综合到这里面#在python中基于pymysql调用
cursor.callproc('p1')print(cursor.fetchall())
创建简单存储过程
储存方式进行传参
delimiter //create procedure p2(in n1 int, #n1参数是需要传入的,也就是接收外部数据的,并且这个数据必须是int类型
inn2 int
)
BEGIN
select* from blog where id > n1; #直接应用变量
END //delimiter ;#调用存储过程的两种方式:或者说是两个地方吧
#在mysql中调用
call p2(3,2)#在python中基于pymysql调用
cursor.callproc('p2',(3,2))print(cursor.fetchall())
一、数学函数
ROUND(x,y)
返回参数x的四舍五入的有y位小数的值
RAND()
返回0到1内的随机值,可以通过提供一个参数(种子)使RAND()随机数生成器生成一个指定的值。
二、聚合函数(常用于GROUP BY从句的SELECT查询中)
AVG(col)返回指定列的平均值
COUNT(col)返回指定列中非NULL值的个数
MIN(col)返回指定列的最小值
MAX(col)返回指定列的最大值
SUM(col)返回指定列的所有值之和
GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果
三、字符串函数
CHAR_LENGTH(str)
返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。
CONCAT(str1,str2,...)
字符串拼接
如有任何一个参数为NULL ,则返回值为 NULL。
CONCAT_WS(separator,str1,str2,...)
字符串拼接(自定义连接符)
CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。
CONV(N,from_base,to_base)
进制转换
例如:
SELECT CONV('a',16,2); 表示将 a 由16进制转换为2进制字符串表示
FORMAT(X,D)
将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若 D 为 0, 则返回结果不带有小数点,或不含小数部分。
例如:
SELECT FORMAT(12332.1,4); 结果为: '12,332.1000'INSERT(str,pos,len,newstr)
在str的指定位置插入字符串
pos:要替换位置其实位置
len:替换的长度
newstr:新字符串
特别的:
如果pos超过原字符串长度,则返回原字符串
如果len超过原字符串长度,则由新字符串完全替换
INSTR(str,substr)
返回字符串 str 中子字符串的第一个出现位置。
LEFT(str,len)
返回字符串str 从开始的len位置的子序列字符。
LOWER(str)
变小写
UPPER(str)
变大写
REVERSE(str)
返回字符串 str ,顺序和字符顺序相反。
SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。 使用 FROM的格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。
mysql> SELECT SUBSTRING('Quadratically',5);-> 'ratically'mysql> SELECT SUBSTRING('foobarbar' FROM 4);-> 'barbar'mysql> SELECT SUBSTRING('Quadratically',5,6);-> 'ratica'mysql> SELECT SUBSTRING('Sakila', -3);-> 'ila'mysql> SELECT SUBSTRING('Sakila', -5, 3);-> 'aki'mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);-> 'ki'四、日期和时间函数
CURDATE()或CURRENT_DATE() 返回当前的日期
CURTIME()或CURRENT_TIME() 返回当前的时间
DAYOFWEEK(date) 返回date所代表的一星期中的第几天(1~7)
DAYOFMONTH(date) 返回date是一个月的第几天(1~31)
DAYOFYEAR(date) 返回date是一年的第几天(1~366)
DAYNAME(date) 返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
FROM_UNIXTIME(ts,fmt) 根据指定的fmt格式,格式化UNIX时间戳ts
HOUR(time) 返回time的小时值(0~23)
MINUTE(time) 返回time的分钟值(0~59)
MONTH(date) 返回date的月份值(1~12)
MONTHNAME(date) 返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
NOW() 返回当前的日期和时间
QUARTER(date) 返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);
WEEK(date) 返回日期date为一年中第几周(0~53)
YEAR(date) 返回日期date的年份(1000~9999)
重点:
DATE_FORMAT(date,format) 根据format字符串格式化date值
mysql> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');-> 'Sunday October 2009'mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');-> '22:23:00'mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',-> '%D %y %a %d %m %b %j');-> '4th 00 Thu 04 10 Oct 277'mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',-> '%H %k %I %r %T %S %w');-> '22 22 10 10:23:00 PM 22:23:00 00 6'mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');-> '1998 52'mysql> SELECT DATE_FORMAT('2006-06-00', '%d');-> '00'五、加密函数
MD5()
计算字符串str的MD5校验和
PASSWORD(str)
返回字符串str的加密版本,这个加密过程是不可逆转的,和UNIX密码加密过程使用不同的算法。
六、控制流函数
CASE WHEN[test1] THEN [result1]...ELSE [default] END
如果testN是真,则返回resultN,否则返回default
CASE [test] WHEN[val1] THEN [result]...ELSE [default]END
如果test和valN相等,则返回resultN,否则返回default
IF(test,t,f)
如果test是真,返回t;否则返回f
IFNULL(arg1,arg2)
如果arg1不是空,返回arg1,否则返回arg2
NULLIF(arg1,arg2)
如果arg1=arg2返回NULL;否则返回arg1
mysql函数运用
delimiter //CREATE PROCEDURE proc_if ()
BEGIN
declare i int default 0;if i = 1THEN
SELECT1;
ELSEIF i= 2THEN
SELECT2;
ELSE
SELECT7;
END IF;
END//delimiter ;
delimiter//CREATE PROCEDURE proc_while ()
BEGIN
DECLARE num INT ;
SET num=0 ;
WHILE num< 10DO
SELECT
num ;
SET num= num + 1;
END WHILE ;
END//delimiter ;
mysql流程if控制,while循环