Передать массив в хранимую подпрограмму MySQL - PullRequest
46 голосов
/ 16 ноября 2011

Мне нужно передать массив строк в качестве параметра хранимой подпрограмме MySQL.Массив может быть длинным, и его количество элементов не фиксировано.Затем я хочу поместить строковые значения в таблицу в памяти с одним столбцом, чтобы я мог работать с данными.Я не знаю, можно ли это сделать в MySQL.Возможно, нужны грязные обходные пути.

Например, у меня есть строковые значения:

Banana, Apple, Orange

Теперь я хочу получить данные об этих фруктах из моей таблицы 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

Microsoft SQL Server позволяет использовать тип данных TEXT и отправлять массив в виде строки XML, быстро создавая таблицу в памяти.Однако я не думаю, что такая техника возможна в MySQL.

Любая помощь в том, как это сделать, была бы признательна!

Ответы [ 7 ]

55 голосов
/ 16 ноября 2011

Вы можете передать строку со своим списком и использовать подготовленные операторы для запуска запроса, например, -

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 ;

Как использовать:

SET @fruitArray = '\'apple\',\'banana\'';
CALL GetFruits(@fruitArray);
27 голосов
/ 14 октября 2012

Просто используйте FIND_IN_SET примерно так:

mysql> SELECT FIND_IN_SET('b','a,b,c,d');
        -> 2

, так что вы можете сделать:

15 голосов
/ 02 октября 2013

Это помогает мне сделать В НАСТОЯЩЕМ состоянии. Надеюсь, что это поможет вам.

9 голосов
/ 14 апреля 2013

Использовать объединение с временной таблицей. Вам не нужно передавать временные таблицы в функции, они глобальные .

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
3 голосов
/ 15 апреля 2013

Если вы не хотите использовать временные таблицы, здесь есть функция, подобная разделенной строке, которую вы можете использовать

SET @Array = 'one,two,three,four';
SET @ArrayIndex = 2;
SELECT CASE 
    WHEN @Array REGEXP CONCAT('((,).*){',@ArrayIndex,'}') 
    THEN SUBSTRING_INDEX(SUBSTRING_INDEX(@Array,',',@ArrayIndex+1),',',-1) 
    ELSE NULL
END AS Result;
  • SUBSTRING_INDEX(string, delim, n) возвращает первое n
  • SUBSTRING_INDEX(string, delim, -1) возвращает только последний
  • REGEXP '((delim).*){n}' проверяет наличие n разделителей (т. Е. Вы находитесь в границах)
3 голосов
/ 18 ноября 2011

Я нашел неуклюжее, но функциональное решение для моей проблемы. Это работает для одномерного массива (больше измерений будет сложно) и ввода, который вписывается в 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;

Например, ввод для этого кода может быть строкой Apple|Banana|Orange. MyTemporaryTable будет заполнен тремя строками, содержащими строки Apple, Banana и Orange соответственно.

Я думал, что медленная скорость обработки строк сделает этот подход бесполезным, но он был достаточно быстрым (всего лишь доли секунды для массива 1000 записей).

Надеюсь, это кому-нибудь поможет.

1 голос
/ 13 марта 2013

Это симулирует массив символов, но вы можете заменить SUBSTR на ELT для имитации массива строк

declare t_tipos varchar(255) default 'ABCDE';
declare t_actual char(1);
declare t_indice integer default 1;
while t_indice<length(t_tipos)+1 do
    set t_actual=SUBSTR(t_tipos,t_indice,1);
        select t_actual;
        set t_indice=t_indice+1;
end while;
...