将数组传递给MySQL存储例程

Gru*_*ber 53 mysql arrays stored-procedures parameter-passing

我需要将一个字符串数组作为参数传递给MySQL存储的例程.该数组可能很长,其元素数量不固定.然后,我想将字符串值放入具有一列的内存表中,因此我可以处理数据.我不知道这是否可以在MySQL中完成.可能需要肮脏的解决方法.

例如,我有字符串值:

Banana, Apple, Orange
Run Code Online (Sandbox Code Playgroud)

现在我想从MySQL Fruits表中获取这些水果的数据.伪代码:

create function GetFruits(Array fruitArray) 
   declare @temp table as
      fruitName varchar(100)
   end

   @temp = convert fruitArray to table
   select * from Fruits where Name in (select fruitName from @temp)
end
Run Code Online (Sandbox Code Playgroud)

Microsoft SQL Server允许您使用TEXT数据类型并将数组作为XML字符串提交,从而快速创建内存表.但是,我不认为这种技术在MySQL中是可行的.

任何有关如何做到这一点的帮助将不胜感激!

Dev*_*art 62

您可以使用列表传递字符串并使用预准备语句来运行查询,例如 -

DELIMITER $$

CREATE PROCEDURE GetFruits(IN fruitArray VARCHAR(255))
BEGIN

  SET @sql = CONCAT('SELECT * FROM Fruits WHERE Name IN (', fruitArray, ')');
  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;

END
$$

DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

如何使用:

SET @fruitArray = '\'apple\',\'banana\'';
CALL GetFruits(@fruitArray);
Run Code Online (Sandbox Code Playgroud)

  • 这种方法是否容易受到SQL注入攻击? (23认同)
  • 那太烂了.我要说使用临时表的连接. (4认同)
  • 如果输入(例如,来自用户)包括未经过清理的逗号,则这可能会中断. (3认同)
  • 我真的很惊讶,可以接受的答案会在系统中造成较大的安全漏洞 (3认同)

Sag*_*fek 31

只需使用FIND_IN_SET:

mysql> SELECT FIND_IN_SET('b','a,b,c,d');
        -> 2
Run Code Online (Sandbox Code Playgroud)

所以你可以这样做:

select * from Fruits where FIND_IN_SET(fruit, fruitArray) > 0
Run Code Online (Sandbox Code Playgroud)

  • 也适用于整数:FIND_IN_SET(product.Id,'1,2,3') (3认同)
  • 唯一的缺点是它比存储过程选项慢 (2认同)

Raj*_*Raj 19

这有助于我做IN状态希望这会帮助你..

CREATE  PROCEDURE `test`(IN Array_String VARCHAR(100))
BEGIN
    SELECT * FROM Table_Name
    WHERE FIND_IN_SET(field_name_to_search, Array_String);

END//;
Run Code Online (Sandbox Code Playgroud)

呼叫:

 call test('3,2,1');
Run Code Online (Sandbox Code Playgroud)


bob*_*obo 10

使用临时表的连接.您不需要将临时表传递给函数,它们是全局的.

create temporary table ids( id int ) ;
insert into ids values (1),(2),(3) ;

delimiter //
drop procedure if exists tsel //
create procedure tsel() -- uses temporary table named ids. no params
READS SQL DATA
BEGIN
  -- use the temporary table `ids` in the SELECT statement or
  -- whatever query you have
  select * from Users INNER JOIN ids on userId=ids.id ;
END //
DELIMITER ;

CALL tsel() ; -- call the procedure
Run Code Online (Sandbox Code Playgroud)


Gru*_*ber 5

我为我的问题想出了一个笨拙但实用的解决方案。它适用于一维数组(更多维度会很棘手)和适合以下形式的输入varchar

  declare pos int;           -- Keeping track of the next item's position
  declare item varchar(100); -- A single item of the input
  declare breaker int;       -- Safeguard for while loop 

  -- The string must end with the delimiter
  if right(inputString, 1) <> '|' then
     set inputString = concat(inputString, '|');
  end if;

  DROP TABLE IF EXISTS MyTemporaryTable;
  CREATE TEMPORARY TABLE MyTemporaryTable ( columnName varchar(100) );
  set breaker = 0;

  while (breaker < 2000) && (length(inputString) > 1) do
     -- Iterate looking for the delimiter, add rows to temporary table.
     set breaker = breaker + 1;
     set pos = INSTR(inputString, '|');
     set item = LEFT(inputString, pos - 1);
     set inputString = substring(inputString, pos + 1);
     insert into MyTemporaryTable values(item);
  end while;
Run Code Online (Sandbox Code Playgroud)

例如,此代码的输入可以是字符串Apple|Banana|OrangeMyTemporaryTable将填充分别包含字符串AppleBanana和 的三行Orange

我认为字符串处理速度慢会使这种方法毫无用处,但它足够快(对于 1,000 个条目的数组来说只有几分之一秒)。

希望这对某人有帮助。