在MySQL中如何将整数列表传递给存储过程中的预准备语句?

时间:2014-04-11 03:03:17

标签: mysql sql prepared-statement argument-passing

MySQL 5.0

CREATE TABLE `locationcodes` (
  `id` int,
  `customer` varchar(100),
  `locationcode` varchar(50),
  `parentid` int
);

insert into locationcodes values (1, 'Test, Inc.', 'California', NULL);
insert into locationcodes values (2, 'Test, Inc.', 'Los Angeles', 1);
insert into locationcodes values (3, 'Test, Inc.', 'San Francisco', 1);
insert into locationcodes values (4, 'Test, Inc.', 'Sacramento', 1);

存储过程:

CREATE PROCEDURE test (_location VARCHAR(100))
BEGIN

SET @location = _location;

SET @select='
  SELECT id, locationcode
  FROM locationcodes  
  WHERE customer="Test, Inc."
  AND id in (?)
  ';

PREPARE stmt FROM @select;
EXECUTE stmt USING @location;
DEALLOCATE PREPARE stmt;

END

通话程序:

call test('2, 3')

结果:

2, Los Angeles

结果只有一行,但我想要两行。挑战是准备好的语句看到参数是一个varchar,并相应地在值周围加上引号。我不想引用任何引号,以便我可以构建一个IN语句,怎么能这样做呢?理想情况下,MySQL会有一个int数据类型的列表,所以我不必使用varchar,但这不存在。

我需要保留准备好的语句以防止sql注入攻击。

1 个答案:

答案 0 :(得分:1)

似乎无法使用带有IN()的预准备语句并绑定一个值。

出于某种原因,当在相应的比较中只有一个值要绑定时,MySQL的API用=(相等)替换IN()。

我用我们的程序进行了一些测试,这是我得到的。

使用MySQL生成的原始程序(test是我的默认数据库):

((`test`.`locationcodes`.`customer` = 'Test, Inc.') and 
(`test`.`locationcodes`.`id` = '2,3'))

在这种情况下,字段id是整数,MySQL转换为' 2,3'比较中的2,这就是它返回洛杉矶的原因,' 3,2'将返回旧金山'明显。

为了确保这与字段类型(id为整数)无关,我试图将该值与locationcode(varchar)进行比较,结果是相同的。

我将您的程序更改为绑定两个值而不是一个。

...
SET @select='
  SELECT id, locationcode
  FROM locationcodes  
  WHERE customer="Test, Inc."
  AND id in (?,?)
  ';

PREPARE stmt FROM @select;
EXECUTE stmt USING @location,@location2;
...

在这种情况下,正确创建语句。

((`test`.`locationcodes`.`customer` = 'Test, Inc.') and 
(`test`.`locationcodes`.`id` in ('2','3')))

话虽如此,我可以告诉你,必须使用另一种方法,通过准备好的陈述来实现这一目标。

我的测试后发现了这个错误报告http://bugs.mysql.com/bug.php?id=16564

根据Valeriy,使用值创建一个临时表并使用JOIN。它应该工作。