我需要将一个字符串数组作为参数传递给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中是可行的。
任何有关如何做到这一点的帮助将不胜感激!
答案 0 :(得分:56)
您可以在列表中传递一个字符串,并使用prepared statements来运行查询,例如 -
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);
答案 1 :(得分:25)
只需使用FIND_IN_SET:
mysql> SELECT FIND_IN_SET('b','a,b,c,d');
-> 2
所以你可以这样做:
select * from Fruits where FIND_IN_SET(fruit, fruitArray) > 0
答案 2 :(得分:15)
这有助于我做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');
答案 3 :(得分:9)
使用临时表的连接。您不需要将临时表传递给函数they are global。
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
答案 4 :(得分:3)
我为我的问题想出了一个尴尬但功能强大的解决方案。它适用于一维数组(更多维度会很棘手)和适合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
。
我认为字符串处理的速度慢会使这种方法变得无用,但它足够快(对于1,000个条目数组只有几分之一秒)。
希望这有助于某人。
答案 5 :(得分:3)
如果您不想使用临时表,则可以使用
这样的分割字符串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)
返回第一个SUBSTRING_INDEX(string, delim, -1)
返回最后一个REGEXP '((delim).*){n}'
检查是否有n个分隔符(即你在界限内)答案 6 :(得分:1)
这模拟了一个字符数组,但你可以用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;
答案 7 :(得分:1)
我不确定这是否能完全回答问题(不是),但这是我为类似问题想到的解决方案。在这里,我尝试每个定界符只使用一次LOCATE()。
-- *****************************************************************************
-- 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');