Mysql 将IN()子句与存储过程一起使用

Mysql 将IN()子句与存储过程一起使用,mysql,Mysql,我有一个存储过程,它接受一个与下面相同的参数: getData ( param varchar(500) ) BEGIN SELECT * FROM category WHERE ID in ( param ); END 给定参数为1,2,3,我如何使它成为1,2,3,而不使用varchar来执行与1,2,2中的ID相同的查询,而不是与1,2,3中的ID相同?非常难看,因为mysql存储过程目前不支持数组类型的参数: 示例调用: 完整脚本: 给定param类似于“1,2,3”,

我有一个存储过程,它接受一个与下面相同的参数:

getData (
  param varchar(500)
)
BEGIN
  SELECT *
  FROM category
  WHERE ID in ( param );
END

给定参数为1,2,3,我如何使它成为1,2,3,而不使用varchar来执行与1,2,2中的ID相同的查询,而不是与1,2,3中的ID相同?

非常难看,因为mysql存储过程目前不支持数组类型的参数:

示例调用:

完整脚本:


给定param类似于“1,2,3”,您可以创建prepared语句,然后执行它

SET query = CONCAT('SELECT * FROM category WHERE ID in (',param,')');
PREPARE stmt FROM query;
EXECUTE stmt;

这是一个正在形成的SQL注入漏洞。如果存在SQL注入的可能性,尝试在存储过程中进行防御性编程或与数据库或其数据无关的操作可能会导致无法维护的混乱。我说,如果可能的话,应该由程序员来传递有效参数或避免存储过程。问题不是存储过程。它是对部分由用户输入生成的代码进行评估。这在任何语言中都是一个糟糕的想法,不仅仅是SQL。正如上面f00非常出色地演示的那样,可以使用SQL解决此问题,而不会像代码那样引入漏洞。
drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
username varchar(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');
SET query = CONCAT('SELECT * FROM category WHERE ID in (',param,')');
PREPARE stmt FROM query;
EXECUTE stmt;