数据库之mysql存储程序

时间:2023-03-08 23:43:36
数据库之mysql存储程序

什么时候会用到存储过程

1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度
2.当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query,Delete 时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。这些操作,如果用程序来完成,就变成了一条条的 SQL 语句,可能要多次连接数据库。而换成存储,只需要连接一次数据库就可以了

间接:人调用应用程序 应用程序调用过程
直接:通过sqlplus或其它数据库管理工具直接调用过程

heidisql 中创建存储过程与函数

This chapter discusses stored programs and views, which are database objects defined in terms of SQL code that is stored on the server for later execution.

Stored programs include these objects:

    Stored routines, that is, stored procedures and functions. A stored procedure is invoked using the CALL statement. A procedure does not have a return value but can modify its parameters for later inspection by the caller. It can also generate result sets to be returned to the client program. A stored function is used much like a built-in function. you invoke it in an expression and it returns a value during expression evaluation.

    Triggers. A trigger is a named database object that is associated with a table and that is activated when a particular event occurs for the table, such as an insert or update.

    Events. An event is a task that the server runs according to schedule. 

Views are stored queries that when referenced produce a result set. A view acts as a virtual table.

This chapter describes how to use stored programs and views. The following sections provide additional information about SQL syntax for statements related to these objects:

    For each object type, there are CREATE, ALTER, and DROP statements that control which objects exist and how they are defined. See Section 14.1, “Data Definition Statements”.

    The CALL statement is used to invoke stored procedures. See Section 14.2.1, “CALL Syntax”.

    Stored program definitions include a body that may use compound statements, loops, conditionals, and declared variables. See Section 14.6, “MySQL Compound-Statement Syntax”. 

In MySQL 5.7, metadata changes to objects referred to by stored programs are detected and cause automatic reparsing of the affected statements when the program is next executed. For more information, see Section 9.10.4, “Caching of Prepared Statements and Stored Programs”.
stored programs
Stored routines
stored procedures
stored functions
Triggers
Events
views
声明方式有两种:
第一种:声明是否是确定性的
DETERMINISTIC和NOT DETERMINISTIC指出一个子程序是否对给定的输入总是产生同样的结果。 如果没有给定任一特征,默认是NOT DETERMINISTIC,所以必须明确指定DETERMINISTIC来声明一个子程序是确定性的。
这里要说明的是:使用NOW() 函数(或它的同义)或者RAND() 函数不会使一个子程序变成非确定性的。对NOW()而言,二进制日志包括时间戳并会被正确的执行。RAND()只要在一个子程序内被调用一次也可以被正确的复制。所以,可以认为时间戳和随机数种子是子程序的确定性输入,它们在主服务器和从服务器上是一样的。 第二种:声明是否会改变数据  
CONTAINS SQL, NO SQL, READS SQL DATA, MODIFIES SQL用来指出子程序是读还是写数据的。
无论NO SQL还是READS SQL DATA都指出,子程序没有改变数据,但是必须明确地指定其中一个,因为如果任何指定,默认的指定是CONTAINS SQL。 默认情况下,如果允许CREATE PROCEDURE 或CREATE FUNCTION 语句被接受,就必须明确地指定DETERMINISTIC 或 NO SQL与READS SQL DATA 中的一个,否则就会产生1418错误。 其中,sp_name参数表示存储过程或函数的名称;
characteristic参数指定存储函数的特性。 CONTAINS SQL表示子程序包含SQL语句,但不包含读或写数据的语句;
NO SQL表示子程序中不包含SQL语句;
READS SQL DATA表示子程序中包含读数据的语句;
MODIFIES SQL DATA表示子程序中包含写数据的语句。 SQL SECURITY { DEFINER | INVOKER }指明谁有权限来执行。
DEFINER表示只有定义者自己才能够执行;
INVOKER表示调用者可以执行。 COMMENT 'string'是注释信息。 说明:修改存储过程使用ALTER PROCEDURE语句,修改存储函数使用ALTER FUNCTION语句。
但是,这两个语句的结构是一样的,语句中的所有参赛都是一样的。
而且,它们与创建存储过程或函数的语句中的参数也是基本一样的。 修改存储过程和函数,只能修改他们的权限,目前MYSQL还不提供对已存在的存储过程和函数代码的修改
如果要修改,只能通过先DROP掉,然后重新建立新的存储过程和函数来实现
CREATE FUNCTION `myfun`(`in_string` VARCHAR(255), `in_find_str` VARCHAR(20), `in_repl_str` VARCHAR(20))
RETURNS VARCHAR(255)
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'ssssssssssssss'
BEGIN
declare l_new_string varchar(255);
declare l_find_pos int;
set l_find_pos=instr(in_string,in_find_str);
if (l_find_pos>0) then
set l_new_string=insert(in_string,l_find_pos,LENGTH(in_find_str),in_repl_str);
else
set l_new_string=in_string;
end if;
return (l_new_string);
END SELECT `myfun`('corresponds to your server', 'on', 'qqqqqqqqqqqqqqq')
CREATE DEFINER=`root`@`%` PROCEDURE `listdata`()
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT 'test_proc'
BEGIN
select * from alert where type=14;
END call listdata或者下面
CALL `listdata`()
触发器

use spauth;
CREATE TABLE `pre_ucenter_members` (
`uid` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`username` char(128) NOT NULL DEFAULT '',
`password` char(32) NOT NULL DEFAULT '',
`email` char(32) NOT NULL DEFAULT '',
`myid` char(30) NOT NULL DEFAULT '',
`myidkey` char(16) NOT NULL DEFAULT '',
`regip` char(15) NOT NULL DEFAULT '',
`regdate` int(10) unsigned NOT NULL DEFAULT '0',
`lastloginip` int(10) NOT NULL DEFAULT '0',
`lastlogintime` int(10) unsigned NOT NULL DEFAULT '0',
`salt` char(6) NOT NULL,
`secques` char(8) NOT NULL DEFAULT '',
PRIMARY KEY (`uid`),
UNIQUE KEY `username` (`username`),
KEY `email` (`email`)
) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='mysql://root:123456@192.168.1.234:3306/ultrax/pre_ucenter_members';
insert into pre_ucenter_members(username,password,email,salt) select username,md5(CONCAT(PASSWORD,'63b1a2')),username,'63b1a2' from account; create trigger account_bbs
after update on account
for each row
begin
update pre_ucenter_members set password = md5(CONCAT(new.PASSWORD,'63b1a2')) where username = new.username;
end; create trigger account_bbs_insert
after insert on account
for each row
begin
insert into pre_ucenter_members(username,password,email,salt) values(new.username,md5(CONCAT(new.PASSWORD,'63b1a2')),new.username,'63b1a2');
end; 我们如何在触发器引用行的值,也就是说我们要得到我们新插入的订单记录中的gid或much的值。对于insert而言,新插入的行用new来表示,行中的每一列的值用new.列名来表示。 触发器new-old
http://www.cnblogs.com/zzwlovegfj/archive/2012/07/04/2576989.html
new-old的理解
http://www.chenyudong.com/archives/database-trigger-new-old-value-understand.html
1.实验创建触发器
2.实验创建事件(计划) 触发器
某表任意一行有变动就更新另一张表中的某字段
CREATE DEFINER=`root`@`%` TRIGGER `ff` AFTER UPDATE ON `expert_history_operation` FOR EACH ROW BEGIN
update en_project set proj_code = 'uuuuu' where xpmobs_sid = '552';
END navicat执行正常,heidisql执行报错,修改为下面的就可以正常执行,二个客户端语法有所差异,折腾了好久 CREATE PROCEDURE update_invitation_status_proce()
begin
update invitation a set a.status='4' where a.deadlinetime<NOW() and a.status='1';
UPDATE `order_authorization` a SET a.submitStatus = '3' WHERE a.authorizedDeadline < NOW() AND a.submitStatus != '4';
end ; 修改为下面的就可以正常执行 DELIMITER //
CREATE DEFINER=`root`@`%` PROCEDURE `update_invitation_status_proce`()
BEGIN
update invitation a set a.status='4' where a.deadlinetime<NOW() and a.status='1';
UPDATE `order_authorization` a SET a.submitStatus = '3' WHERE a.authorizedDeadline < NOW() AND a.submitStatus != '4';
END//
DELIMITER ; 事件event,执行时间为服务器上的时间点, 前提是show variables like "event_scheduler" 这个值为on,也就是开启状态,事件才能生效
mysql> show variables like "event_scheduler";
mysql> set global event_scheduler = 1;
也可在/etc/my.cnf中在mysqld下面加入一行event_scheduler = 1,但需要重启服务器。所以一般流行的做法是双管齐下,
1.set global event_scheduler = 1;
2.vi /etc/my.cnf加入这一行。
这样的话,不重启也生效,重启后也生效。 可以通过日志查看计划执行效果
[root@my mysql]# tail /var/log/mysqld.log  -f
2016-05-27T22:06:57.225728Z 7 [Note]  - 220.250.64.26
2016-05-30T17:54:54.536231Z 1 [Note] Event Scheduler: Last execution of smartplant.de. Dropping.
2016-05-30T17:54:54.559635Z 9 [Note] Event Scheduler: Dropping smartplant.de
2016-05-30T18:05:18.733466Z 10 [Note] Access denied for user 'root'@'localhost' (using password: YES)
2016-05-30T18:06:45.174233Z 11 [Note] Event Scheduler: Killing the scheduler thread, thread id 1
2016-05-30T18:06:45.174265Z 11 [Note] Event Scheduler: Waiting for the scheduler thread to reply
2016-05-30T18:06:45.174347Z 11 [Note] Event Scheduler: Stopped
2016-05-30T18:16:22.337700Z 12 [Note] Event Scheduler: scheduler thread started with id 12
2016-05-30T18:16:22.337721Z 12 [Note] Event Scheduler: Last execution of smartplant.ww. Dropping.
2016-05-30T18:16:22.345537Z 13 [Note] Event Scheduler: Dropping smartplant.ww
2016-05-30T18:23:25.336330Z 12 [Note] Event Scheduler: Last execution of smartplant.we. CREATE EVENT `we`
 ON SCHEDULE
  AT '2016-05-30 14:23:25'
 ON COMPLETION PRESERVE
 ENABLE
 COMMENT ''
 DO BEGIN
insert into t1 (tid,name) values(7,'g'),(8,'h');
END