如何在MySQL存储过程中拆分逗号分隔文本

时间:2010-02-02 08:23:23

标签: sql mysql

如何在MySQL存储过程中拆分逗号分隔文本(ID列表)以在SQL“IN”语句中使用结果。

SELECT * FROM table WHERE table.id IN (splitStringFunction(commaSeparatedData, ','));

9 个答案:

答案 0 :(得分:40)

这对MySQL来说很简单:

SELECT * FROM table WHERE FIND_IN_SET(table.id, commaSeparatedData);

参考:http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set

答案 1 :(得分:5)

你可以用两种方式做到:

  1. SQL Library
  2. Natively with REGEXP

答案 2 :(得分:5)

您可以在存储过程中使用预准备语句来实现此目的。您可以将整个选择查询创建为变量内的字符串,然后将逗号分隔的字符串连接到其IN子句中。然后,您可以从查询字符串变量中生成预准备语句并执行它。

DELIMITER ;;
create procedure testProc(in listString varchar(255))

BEGIN

set @query = concat('select * from testTable where id in (',listString,');');
prepare sql_query from @query;
execute sql_query;

END
;;

DELIMITER ;

call testProc("1,2,3");

答案 3 :(得分:4)

你可以尝试这个MySql示例。在使用它之前,在那里放一些类型安全检查(即check id是整数,或者在插入之前与正则表达式匹配)。

 # BEGIN split statements ids
 DECLARE current_pos INT DEFAULT 1;
 DECLARE delim CHAR DEFAULT ',';
 DECLARE current CHAR DEFAULT '';
 DECLARE current_id VARCHAR(100) DEFAULT '';;
 CREATE TEMPORARY TABLE ids (`id` VARCHAR(100));
 split_ids: LOOP
  SET current = MID(statement_ids, current_pos, 1);
  IF (current_pos = LENGTH(statement_ids)) THEN
   IF current != delim THEN SET current_id = CONCAT(current_id,current); END IF;
   INSERT INTO ids(id) VALUES (current_id);
   LEAVE split_ids;
  END IF;
  IF current = delim THEN
   INSERT INTO ids(id) VALUES (current_id);
   SET current_id = '';
  ELSE
   SET current_id = CONCAT(current_id,current);
  END IF;
  SET current_pos = current_pos+1;
 END LOOP split_ids;
 # END split statement ids

 # to check ids are correct
 SELECT * FROM ids;

 # to use the ids:
 SELECT * FROM statements WHERE id IN (SELECT id FROM ids);

答案 4 :(得分:2)

好吧,对于像我这样的人来说,稍微“简单”但不那么令人讨厌:

说你有一个表'combined_city_state'看起来像:

'Chicago, Illinois'

将其复制到另外两个表中:

CREATE TABLE city LIKE combined_city_state;
INSERT city SELECT * FROM combined_city_state;

CREATE TABLE state LIKE combined_city_state;
INSERT state SELECT * FROM combined_city_state;

您现在有3个表与'combined_city_state'具有相同的数据。

安装此功能:

CREATE FUNCTION SPLIT_STR(
  x VARCHAR(255),
  delim VARCHAR(12),
  pos INT
)
RETURNS VARCHAR(255)
RETURN REPLACE(SUBSTRING(SUBSTRING_INDEX(x, delim, pos),
       LENGTH(SUBSTRING_INDEX(x, delim, pos -1)) + 1),
       delim, '');

然后将其应用于每个表以删除额外的数据索引:

UPDATE firms 
SET city = (SELECT SPLIT_STR((city), ',', 1));


UPDATE firms 
SET state = (SELECT SPLIT_STR((state), ',', 2));

这将为您留下一列只有城市,只有一个州。如果您不再需要,现在可以删除原始的'combined_city_state'列。

答案 5 :(得分:1)

我很惊讶这里没有正确提到单线:

SELECT * FROM table
WHERE id in (SELECT convert(int,Value) FROM dbo.Split(@list_string,',')

你所需要的只是一个Split SQL function,就像下面的那个一样,它也会以其他方式派上用场:

CREATE FUNCTION dbo.Split
(
    @List nvarchar(2000),
    @SplitOn nvarchar(5)
)  
RETURNS @RtnValue table 
(

    Id int identity(1,1),
    Value nvarchar(100)
) 
AS  
BEGIN
While (Charindex(@SplitOn,@List)>0)
Begin
    Insert Into @RtnValue (value)
    Select 
        Value = ltrim(rtrim(Substring(@List,1,Charindex(@SplitOn,@List)-1)))
        Set @List = Substring(@List,Charindex(@SplitOn,@List)+len(@SplitOn),len(@List))
End

Insert Into @RtnValue (Value)
Select Value = ltrim(rtrim(@List))

Return
END

答案 6 :(得分:0)

我已经用连字符解析了数据。下面的示例使用固定的文本字符串来演示,只需更改表中相关列名的引用。我玩了很长时间以确保它能够处理具有不同数量组件的代码,并最终决定添加where子句。您尝试解析的大多数数据都有固定数量的列。

select
SUBSTRING_INDEX(TS,"-",1) as "1",
reverse(left(reverse(SUBSTRING_INDEX(TS,"-",2)),locate("-",reverse(SUBSTRING_INDEX(TS,"-",2)))-1)) as "2",
reverse(left(reverse(SUBSTRING_INDEX(TS,"-",3)),locate("-",reverse(SUBSTRING_INDEX(TS,"-",3)))-1)) as "3",
reverse(left(reverse(SUBSTRING_INDEX(TS,"-",4)),locate("-",reverse(SUBSTRING_INDEX(TS,"-",4)))-1)) as "4",
reverse(left(reverse(SUBSTRING_INDEX(TS,"-",5)),locate("-",reverse(SUBSTRING_INDEX(TS,"-",5)))-1)) as "5",
reverse(left(reverse(SUBSTRING_INDEX(TS,"-",6)),locate("-",reverse(SUBSTRING_INDEX(TS,"-",6)))-1)) as "6",reverse(left(reverse(SUBSTRING_INDEX(TS,"-",7)),locate("-",reverse(SUBSTRING_INDEX(TS,"-",7)))-1)) as "7",
reverse(left(reverse(SUBSTRING_INDEX(TS,"-",8)),locate("-",reverse(SUBSTRING_INDEX(TS,"-",8)))-1)) as "8",
reverse(left(reverse(SUBSTRING_INDEX(TS,"-",9)),locate("-",reverse(SUBSTRING_INDEX(TS,"-",9)))-1)) as "9",
reverse(left(reverse(SUBSTRING_INDEX(TS,"-",10)),locate("-",reverse(SUBSTRING_INDEX(TS,"-",10)))-1)) as "10"
from (select "aaa-bbb-ccc-ddd-eee-fff-ggg-hhh-iii-jjj" as TS) as S
where (LENGTH(TS)-LENGTH(REPLACE(TS,'-',''))) =9

答案 7 :(得分:0)

有些奇怪,但是:

SET @i = 1;
set @str = 'a,b,c,d,e,f,g,h';

select temp.length into @length from 
(select
        ROUND(   
            (
                LENGTH(dt.data)
                - LENGTH( REPLACE (dt.data, ",", "") ) 
            ) / LENGTH(",")        
        )+1 AS length   
     from (select @str as data) dt
 ) temp;

SET @query = CONCAT('select substring_index(
    substring_index(@str, '','', seq), 
    '','', 
    -1
  ) as letter from seq_', @i, '_to_',@length);

PREPARE q FROM @query;
EXECUTE q;

答案 8 :(得分:0)

您可以使用find_in_set()函数进行收集过滤器

how-to-split-and-search-in-comma-separated-values-in-mysql

SELECT * FROM table WHERE find_in_set(table.id,commaSeparatedData) > 0;