在存储过程中为'in'子句使用MySQL用户定义的变量

时间:2009-10-21 16:09:13

标签: sql mysql stored-procedures

当将一串逗号分隔的id(作为varchar)发送到MySQL存储过程时,我不能将该字符串用作IN子句的一部分,并返回正确的结果。该字符串被截断为十进制,只使用第一个值。

我以为我可以通过准备然后执行语句来解决这个问题,但这仍然只返回第一个值的匹配。

代码示例可能会使事情变得更清晰。我想将以下内容转换为存储过程(使用in子句动态):

select id, name from cities where id in (1,2,3);

这是我使用预准备语句的存储过程:

DROP PROCEDURE IF EXISTS `cities_select_by_ids` $$
CREATE PROCEDURE `cities_select_by_ids`(
    in _cityIds varchar(1000)
)
BEGIN
SET  @cityIds = _cityIds;

PREPARE stmt FROM '
    select
      id,
      name
    from cities
    where id in (?);
';

EXECUTE stmt USING @cityIds;
DEALLOCATE PREPARE stmt;

END $$
DELIMITER ;

调用存储过程我只得到城市'1'的匹配:

call cities_select_by_ids_prepare('1, 2, 3');

这是表和数据的创建和插入脚本:

CREATE TABLE cities (
  id int(10) unsigned NOT NULL auto_increment,
  name varchar(100) NOT NULL,
  PRIMARY KEY  (`id`)
);
insert into cities (name) values ('London'), ('Manchester'), ('Bristol'), ('Birmingham'), ('Brighton');

3 个答案:

答案 0 :(得分:4)

试试这个。

DROP PROCEDURE IF EXISTS `cities_select_by_ids_2`;

CREATE PROCEDURE `cities_select_by_ids_2`(
    in cityIDs varchar(1000)
)

BEGIN

#- ix - index into the list of city IDs
# cid - city ID
SET @ix := 1;
SET @cid := substring_index(cityIDs, ',', @ix);

LOOP_1: 
WHILE (@cid is not null) DO
    SELECT id,  name 
    FROM cities
        WHERE id in (@cid) ;

     #-- substring_index returns complete cityIDs string when index is > number of elements
     IF (length(substring_index(cityIDs, ',', @ix)) >= length(cityIDs)) THEN
          LEAVE LOOP_1;
     END IF;

     SET @ix := @ix + 1;
     SET @cid = substring_index(substring_index(cityIDs, ',', @ix), ',', -1);

END WHILE;
END 

#----
call cities_select_by_ids_2('1, 2');

答案 1 :(得分:3)

另一种选择。

以下查询仅适用于存储过程中受支持的PREPARED语句。 MySQL 5.0我想。这比使用“find_in_set”好多了。对字符串使用双引号“”。

/* Check your mysql version */

BEGIN
SET @sql_text:=concat(
   'SELECT 
      id,
      name
    FROM db.table
    WHERE 
      id IN 
      (',

      /* BEGIN Parameter */
      '91,57',
      /* END Parameter */

      ') ORDER BY id ASC');

PREPARE stmt from @sql_text;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
END

答案 2 :(得分:2)

由于参数化的工作方式,这是不可能的。

最接近你可以得到它:

where find_in_set(id, ?)

但这不会缩放,因为无法使用索引。