【发布时间】:2011-05-03 23:40:33
【问题描述】:
我想将 id '' 或 '1,2,3,4,5,6,7' 的列表传递给存储过程,然后在其中以下列方式使用:col IN (_PARAM)
我已经查看了SET,但它最多可以有 64 个元素。
当我定义存储过程时,我必须使用什么参数类型? 如果我有更多选择,其中一种与另一种相比有什么优势?
【问题讨论】:
标签: sql mysql stored-procedures types
我想将 id '' 或 '1,2,3,4,5,6,7' 的列表传递给存储过程,然后在其中以下列方式使用:col IN (_PARAM)
我已经查看了SET,但它最多可以有 64 个元素。
当我定义存储过程时,我必须使用什么参数类型? 如果我有更多选择,其中一种与另一种相比有什么优势?
【问题讨论】:
标签: sql mysql stored-procedures types
为什么不使用 VARCHAR 将它们作为字符串传递。
【讨论】:
IN ('1','2','3','4') 这样的单独条目传递,所以作为 varchar 传递失败。
不是一个非常优雅的解决方案,但在 MySQL 成熟之前,您的选择是有限的。
将逗号分隔的 id 拆分为标记并插入到内存表中。将内存表连接到您需要的任何其他表...
完整的脚本在这里:http://pastie.org/1266830
drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
username varbinary(32) unique not null
)
engine=innodb;
insert into users (username) values ('a'),('b'),('c'),('d'),('e'),('f'),('g');
drop procedure if exists foo;
delimiter #
create procedure foo
(
in p_id_csv varchar(1024)
)
proc_main:begin
declare v_id varchar(10);
declare v_done tinyint unsigned default 0;
declare v_idx int unsigned default 1;
if p_id_csv is null or length(p_id_csv) <= 0 then
leave proc_main;
end if;
-- split the string into tokens and put into an in-memory table...
create temporary table ids(id int unsigned not null)engine = memory;
while not v_done do
set v_id = trim(substring(p_id_csv, v_idx,
if(locate(',', p_id_csv, v_idx) > 0,
locate(',', p_id_csv, v_idx) - v_idx, length(p_id_csv))));
if length(v_id) > 0 then
set v_idx = v_idx + length(v_id) + 1;
insert into ids values(v_id);
else
set v_done = 1;
end if;
end while;
select
u.*
from
users u
inner join ids on ids.id = u.user_id
order by
u.username;
drop temporary table if exists ids;
end proc_main #
delimiter ;
call foo('2,4,6');
【讨论】:
其实经过一段时间的搜索,我找到了两个解决方案:
一种方式
使用 PREPARE 语句,这样我就可以在查询本身中将 CONCAT '1','2','3' 格式化为 VARCHAR 参数。
所以应该是这样的
SET @query= CONCAT('...WHERE col IN(',_PARAM,') ');
第二种方式
是将像 '1,2,3' 这样的连接列表作为VARCHAR 参数传递,并使用FIND_IN_SET 调用来查找值
这样查询看起来像
... FIND_IN_SET(col,_PARAM)> 0
【讨论】: