- 存储过程和游标核心:
#变量必须声明在最前面 declare noMoreRows bool default false; declare _id int; declare _name varchar(25); #声明游标 declare xxRows cursor for select * from xx; #当游标移动到最后空行时设置noMoreRows为true declare CONTINUE handler for NOT FOUND set noMoreRows=true; #打开游标 open xxRows; #创建临时内存表 drop table if exists xxTem; create temporary table xxTem (id int,name varchar(25), primary key(id)) engine=memory; truncate table xxTem; #遍历游标 repeat #取出数据到变量 fetch xxRows into _id,_name; #过滤掉重复行,将游标取出结果插入到临时表 if not exists(select 1 from xxTem where id=_id) then insert into xxTem(id,name) values(_id,_name); end if; until noMoreRows=1 end repeat; #关闭游标 close xxRows; #根据参数裁剪临时表结果返回 select * from xxTem limit `skip`,`count`;
完整代码CREATE TABLE `xx` ( `id` INT(11) NOT NULL, `name` VARCHAR(45) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB; CREATE DEFINER=`root`@`localhost` PROCEDURE `proc1`(IN `skip` int, IN `count` int) LANGUAGE SQL NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER COMMENT '' BEGIN #变量必须声明在最前面 declare noMoreRows bool default false; declare _id int; declare _name varchar(25); #声明游标 declare xxRows cursor for select * from xx; #当游标移动到最后空行时设置noMoreRows为true declare CONTINUE handler for NOT FOUND set noMoreRows=true; #打开游标 open xxRows; #创建临时内存表 drop table if exists xxTem; create temporary table xxTem (id int,name varchar(25), primary key(id)) engine=memory; truncate table xxTem; #遍历游标 repeat #取出数据到变量 fetch xxRows into _id,_name; #过滤掉重复行,将游标取出结果插入到临时表 if not exists(select 1 from xxTem where id=_id) then insert into xxTem(id,name) values(_id,_name); end if; until noMoreRows=1 end repeat; #关闭游标 close xxRows; #根据参数裁剪临时表结果返回 select * from xxTem limit `skip`,`count`; END
- 动态sql:随机获取某表的若干行下面是存储过程的代码。过程包含三个参数,分别是表名,行数和主键id。过程只支持int类型单主键的表。主键可以省略为空,这样过程会自动查找主键,不过这样比较慢。 rand_data
1 CREATE DEFINER=`root`@`%` PROCEDURE `rand_data`(IN `tbName` VARCHAR(50), IN `rowCnt` INT, IN `tbKey` VARCHAR(50)) 2 LANGUAGE SQL 3 NOT DETERMINISTIC 4 CONTAINS SQL 5 SQL SECURITY DEFINER 6 COMMENT '随机获取若干记录,只适用于单主键表' 7 BEGIN 8 9 #获取主键名 10 IF tbKey IS NOT NULL THEN 11 SET @tbKey=tbKey;#参数里面已经有,这种情况比较快 12 ELSE 13 #参数里面没,从系统表查找主键,比较耗时 14 SELECT @tbKey:=c.COLUMN_NAME 15 FROM 16 INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS t, 17 INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS c 18 WHERE 19 t.TABLE_NAME = c.TABLE_NAME 20 AND t.TABLE_SCHEMA = c.TABLE_SCHEMA 21 AND t.TABLE_SCHEMA = database() 22 AND t.TABLE_NAME = tbName 23 AND t.CONSTRAINT_TYPE = 'PRIMARY KEY'; 24 END IF; 25 26 #获取最大id,最小id和记录数 27 SET @getMaxIdSql = CONCAT('SELECT @maxId:=MAX(', @tbKey, '),', 28 '@minId:=MIN(', @tbKey, '),', 29 '@totalCnt:=COUNT(', @tbKey, ')', 30 ' FROM `', tbName, '`;'); 31 PREPARE getMaxId FROM @getMaxIdSql; 32 EXECUTE getMaxId; 33 DEALLOCATE PREPARE getMaxId; 34 35 #创建临时表 36 DROP TABLE IF EXISTS rand_tt; 37 SET @temTbSql = CONCAT('CREATE TEMPORARY TABLE rand_tt SELECT 0 aid,tb.* FROM `',tbName,'` tb LIMIT 0;'); 38 PREPARE temTb FROM @temTbSql; 39 EXECUTE temTb; 40 DEALLOCATE PREPARE temTb; 41 42 #构建获取一条记录的sql 43 SET @randRowSql = CONCAT('INSERT INTO rand_tt SELECT @cnt:=@cnt+1 aid,tb.* FROM ', 44 tbName, ' tb WHERE tb.', @tbKey, '=?;'); 45 PREPARE addRow FROM @randRowSql; 46 47 #生成随机记录 48 SET @cnt=0; 49 insertLoop: LOOP 50 SET @id=FLOOR(RAND()*(@maxId-@minId)+@minId); 51 IF NOT EXISTS (SELECT id FROM rand_tt WHERE id=@id) THEN 52 EXECUTE addRow USING @id; 53 IF @cnt >= rowCnt OR @cnt >= @totalCnt THEN 54 LEAVE insertLoop; 55 END IF; 56 END IF; 57 END LOOP insertLoop; 58 DEALLOCATE PREPARE addRow; 59 60 #返回数据 61 ALTER TABLE rand_tt DROP COLUMN aid; 62 SELECT * FROM rand_tt; 63 END
- ...