web-dev-qa-db-ja.com

MySQLストアドルーチンに配列を渡す

MySQLストアドルーチンにパラメーターとして文字列の配列を渡す必要があります。配列は長くなる可能性があり、要素の数は固定されていません。次に、文字列値を1列のメモリ内テーブルに入れて、データを操作できるようにします。これを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でこの手法が可能だとは思いません。

これを行う方法についての助けをいただければ幸いです!

50
Gruber

リストに文字列を渡し、 準備済みステートメント を使用してクエリを実行できます。 -

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);
58
Devart

単純に FIND_IN_SET を使用してください:

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

あなたができるように:

select * from Fruits where FIND_IN_SET(fruit, fruitArray) > 0
29
Sagiv Ofek

これは私が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//;

呼び出し:

 call test('3,2,1');
18
Raj

一時テーブルとの結合を使用します。関数に一時テーブルを渡す必要はありません それらはグローバルです

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
9
bobobobo

ここで一時テーブルを使用したくない場合は、使用できる関数のような分割文字列です

_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
KCD

私の問題に対する厄介だが機能的な解決策を思いついた。 1次元配列(より多くの次元は扱いにくい)と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|OrangeMyTemporaryTableには、文字列AppleBanana、およびOrangeをそれぞれ含む3つの行が入力されます。

文字列処理の速度が遅いと、このアプローチは役に立たないだろうと思いましたが、十分に高速でした(1,000エントリの配列の場合、ほんの一瞬です)。

これが誰かを助けることを願っています。

3
Gruber

これは文字配列をシミュレートしますが、ELTの代わりにSUBSTRを使用して文字列配列をシミュレートできます

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
pvilas