Przekazanie tablicy do procedury przechowywanej w MySQL

Muszę przekazać tablicę łańcuchów jako parametr do procedury przechowywanej w MySQL. Tablica może być długa, a jej liczba elementów nie jest stała. Następnie chcę umieścić wartości łańcuchowe w tabeli w pamięci z jedną kolumną, więc mogę pracować z danymi. Nie wiem czy da się to zrobić w MySQL. Może potrzebne są brudne obejścia.

Na przykład mam wartości łańcuchowe:

Banana, Apple, Orange

Teraz chcę pobrać dane o tych owocach z mojej tabeli MySQL Fruits. Pseudo kod:

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 pozwala na użycie typu danych TEXT i przesłanie tablicy jako ciągu XML, szybko tworząc tabelę w pamięci. Nie sądzę jednak, aby ta technika była możliwa w MySQL.

Każda pomoc, jak to zrobić, będzie mile widziana!

Author: Giacomo1968, 2011-11-16

8 answers

Możesz przekazać ciąg znaków ze swoją listą i użyć prepared statements do uruchomienia zapytania, np.-

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 ;

Jak używać:

SET @fruitArray = '\'apple\',\'banana\'';
CALL GetFruits(@fruitArray);
 66
Author: Devart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-16 11:30:36

Po prostu użyj FIND_IN_SET w ten sposób:

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

Więc możesz zrobić:

select * from Fruits where FIND_IN_SET(fruit, fruitArray) > 0
 36
Author: Sagiv Ofek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-14 15:55:39

To pomaga mi zrobić w Warunkach Mam nadzieję, że to ci pomoże..

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

END//;

Wywołanie:

 call test('3,2,1');
 21
Author: Raj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-02 05:33:19

Użyj join z tymczasową tabelą. Nie musisz przekazywać tabel tymczasowych do funkcji, są one globalne .

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
 12
Author: bobobobo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-14 05:07:35

Wymyśliłem niezręczne, ale funkcjonalne rozwiązanie mojego problemu. To działa dla tablicy jednowymiarowej (więcej wymiarów byłoby trudne) i wejścia, które pasuje do 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;

Na przykład, wejście dla tego kodu może być ciągiem znaków Apple|Banana|Orange. MyTemporaryTable zostanie wypełniona trzema wierszami zawierającymi ciągi znaków Apple, Banana, i Orange odpowiednio.

Myślałem, że powolna prędkość obsługi strun uczyni to podejście bezużytecznym, ale było wystarczająco szybkie (tylko ułamek drugie dla tablicy 1000 wpisów).

Mam nadzieję, że to komuś pomoże.
 3
Author: Gruber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-22 05:12:28

Jeśli nie chcesz używać tabel tymczasowych tutaj jest podzielony łańcuch jak funkcja możesz użyć

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) zwraca pierwsze n
  • SUBSTRING_INDEX(string, delim, -1) zwraca tylko ostatnią
  • REGEXP '((delim).*){n}' sprawdza, czy istnieje N ograniczników (tzn. jesteś w granicach)
 3
Author: KCD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-14 22:07:58

To symuluje tablicę znaków, ale możesz zastąpić PODPR ELT, aby symulować tablicę łańcuchów

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;
 1
Author: pvilas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-13 15:17:38

Nie jestem pewien, czy to w pełni odpowiada na pytanie( nie jest), ale jest to rozwiązanie, które wymyśliłem dla mojego podobnego problemu. Tutaj staram się użyć LOCATE () tylko raz na delimiter.

-- *****************************************************************************
-- test_PVreplace

DROP FUNCTION IF EXISTS test_PVreplace;

delimiter //
CREATE FUNCTION test_PVreplace (
   str TEXT,   -- String to do search'n'replace on
   pv TEXT     -- Parameter/value pairs 'p1=v1|p2=v2|p3=v3'
   )
   RETURNS TEXT

-- Replace specific tags with specific values.

sproc:BEGIN
   DECLARE idx INT;
   DECLARE idx0 INT DEFAULT 1;   -- 1-origined, not 0-origined
   DECLARE len INT;
   DECLARE sPV TEXT;
   DECLARE iPV INT;
   DECLARE sP TEXT;
   DECLARE sV TEXT;

   -- P/V string *must* end with a delimiter.

   IF (RIGHT (pv, 1) <> '|') THEN
      SET pv = CONCAT (pv, '|');
      END IF;

   -- Find all the P/V pairs.

   SELECT LOCATE ('|', pv, idx0) INTO idx;
   WHILE (idx > 0) DO
      SET len = idx - idx0;
      SELECT SUBSTRING(pv, idx0, len) INTO sPV;

      -- Found a P/V pair.  Break it up.

      SELECT LOCATE ('=', sPV) INTO iPV;
      IF (iPV = 0) THEN
         SET sP = sPV;
         SET sV = '';
      ELSE
         SELECT SUBSTRING(sPV, 1, iPV-1) INTO sP;
         SELECT SUBSTRING(sPV, iPV+1) INTO sV;
         END IF;

      -- Do the substitution(s).

      SELECT REPLACE (str, sP, sV) INTO str;

      -- Do next P/V pair.

      SET idx0 = idx + 1;
      SELECT LOCATE ('|', pv, idx0) INTO idx;
      END WHILE;
   RETURN (str);
END//
delimiter ;

SELECT test_PVreplace ('%one% %two% %three%', '%one%=1|%two%=2|%three%=3');
SELECT test_PVreplace ('%one% %two% %three%', '%one%=I|%two%=II|%three%=III');
SELECT test_PVreplace ('%one% %two% %three% - %one% %two% %three%', '%one%=I|%two%=II|%three%=III');
SELECT test_PVreplace ('%one% %two% %three% - %one% %two% %three%', '');
SELECT test_PVreplace ('%one% %two% %three% - %one% %two% %three%', NULL);
SELECT test_PVreplace ('%one% %two% %three%', '%one%=%two%|%two%=%three%|%three%=III');
 1
Author: Alan Stewart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-24 00:34:02