两者都能实现将完成特定功能的多条 SQL 语句进行封装,以简单的方式供程序进行调用。
两者区别:
- Function 总是返回一个值,而 Procedure 可以返回多个值或没有返回值,但不能使用
return
关键字返回; - Function 可以跟普通表达式或函数一样调用,而 Procedure 使用
call
关键字调用; - Procedure 可以使用
INT
,OUT
,INOUT
参数类型,而 Function 只有INT
参数。
添加函数
create function hello (s char(20)) returns char(50) DETERMINISTIC
return concat('hello, ', s, '!');
查看函数定义
show create function sequence\G
调用函数
select hello('World');
删除函数
drop function hello;
查看所有函数
show function status where db = 'test'\G
添加存储过程
create procedure simpleproc (out param1 int)
begin
select count(*) into param1 from t;
end
调用存储过程
CALL simpleproc(@a);
获取返回值
SELECT @a;
查看存储过程的定义
show create procedure simpleproc\G
删除存储过程
drop procedure simpleproc;
查看所有存储过程
show procedure status where db = 'test'\G
create table sequence (
`name` tinyint(3) unsigned not null,
`val` bigint(20) unsigned not null,
primary key (`name`)
) engine = innodb;
name
用于标识业务,val
为递增 ID。
insert into sequence (name, val) values (1, 0);
由于是通过不停 update
同一个 name
的 val
实现值的递增,因此一开始必须存在该记录。
create function sequence (n tinyint) returns bigint
begin
declare result bigint unsigned;
update sequence set val = last_insert_id(val+1) where name = n;
set result = last_insert_id();
return result;
end
update
语句是原子的,而 last_insert_id()
在不同连接之间相互不影响,因此可以通过该函数获取全局唯一的 ID。
select sequence(1);
每次调用 sequence(1)
函数都可以获取一个全局唯一的 ID。
该例子是上面例子的衍生。
create procedure `sequence_batch`(in name tinyint, in num int)
begin
declare s int;
set session sql_log_bin = off;
set s = 0;
create temporary table if not exists tb (id bigint) engine = myisam;
start transaction;
while s < num do
insert into tb select sequence(name);
set s = s +1;
end while;
commit;
select * from tb;
drop table tb;
set session sql_log_bin = on;
end
根据所需的 ID 数量,将逐个生成的 ID 先存放在一个临时表,最后将它们一次性全部读取出来作为结果返回。
call sequence_batch(1, 1000);
单次获取的 ID 数量越多,该方法所需的执行时间就越长。
- 在存储过程和函数中,可以使用游标对结果集进行遍历处理,以便对每行数据进行操作。
- 有时,需要在检索出来的行中前进或后退一行或多行,这就是使用游标的原因。
- 游标主要用于交互式的应用,其中用户滚动屏幕上的数据,并对数据进行浏览或作出变更。
在表数据发生变化时自动触发执行某些语句,添加、删除、修改操作都支持使用触发器。
create trigger neworder after insert on orders
for each row select NEW.order_num into @order_num;
每添加一条记录都将它的订单号查询出来赋值给 order_num
变量,其中 NEW
表示新添加的记录。
create trigger updateorder before update on orders
for each row set NEW.order_state = upper(NEW.order_state);
当订单状态发生变化时,将状态值转换成大写再更新回去,其中 OLD
表示更新前的记录,NEW
表示更新后的记录。
create trigger deleteorder before delete on orders
for each row
begin
insert into archive_orders(order_num, order_date, cust_id)
values (OLD.order_num, OLD.order_date, OLD.cust_id);
end;
将删除后的记录备份到 archive_orders
表,其中 OLD
表示被删除的记录。