【问题标题】:MySQL Split Comma Separated String Into Temp TableMySQL将逗号分隔的字符串拆分为临时表
【发布时间】:2026-02-25 19:45:01
【问题描述】:

你能在 MySQL 中使用 RegEx 将逗号分隔的字符串解析成临时表吗?

'1|2|5|6' into temp table with 4 rows.

【问题讨论】:

  • 这似乎不需要正则表达式。
  • 我经常使用 MySQL(看看我的其他一些答案),但我永远不会在 SQL 中这样做。任何脚本语言都更适合这项任务。为工作使用正确的工具。

标签: mysql regex


【解决方案1】:

这个问题和Can Mysql Split a column?差不多

MySQL 没有拆分字符串功能,因此您必须解决问题。使用上面答案页面上列出的方法之一拆分数据后,您可以对数据执行任何操作。

您可以遍历该自定义函数并在它返回空时中断,您必须玩并学习一些语法(或者至少我会)但是 mysql 中 FOR 循环的语法在这里: http://www.roseindia.net/sql/mysql-example/for.shtml

您可以对其进行迭代,在下面的函数中递增位置:

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, '');

(信用:https://blog.fedecarg.com/2009/02/22/mysql-split-string-function/

如果没有找到匹配项,应该返回 '',所以如果没有找到匹配项就中断循环。这将允许您仅使用 mysql 解析拆分字符串并将插入查询运行到临时表中。但是人为什么不直接使用像 php 这样的脚本语言来完成这种工作呢? :(

循环语法代码:

DELIMITER $$  

CREATE PROCEDURE ABC(fullstr)

   BEGIN
      DECLARE a INT Default 0 ;
      DECLARE str VARCHAR(255);
      simple_loop: LOOP
         SET a=a+1;
         SET str=SPLIT_STR(fullstr,"|",a);
         IF str='' THEN
            LEAVE simple_loop;
         END IF;
         #Do Inserts into temp table here with str going into the row
         insert into my_temp_table values (str);
   END LOOP simple_loop;
END $$

【讨论】:

  • 这会获取一个值,而不是整个列表到临时表中。
  • 列表中的每一项都需要一行吗?
  • 是的,所以我可以利用索引
  • 函数 SPLIT_STR 因超过一个字节的字符大小而失败。使用CHAR_LENGTH() 而不是LENGTH()
【解决方案2】:

我找到了很好的解决方案

https://forums.mysql.com/read.php?10,635524,635529

感谢彼得·布劳利

技巧:将 csv 字符串上的 Group_Concat() 结果转换为 插入...值...字符串:

drop table if exists t;
create table t( txt text );
insert into t values('1,2,3,4,5,6,7,8,9');

drop temporary table if exists temp;
create temporary table temp( val char(255) );
set @sql = concat("insert into temp (val) values ('", replace(( select group_concat(distinct txt) as data from t), ",", "'),('"),"');");
prepare stmt1 from @sql;
execute stmt1;
select distinct(val) from temp;
+------+
| val  |
+------+
| 1    |
| 2    |
| 3    |
| 4    |
| 5    |
| 6    |
| 7    |
| 8    |
| 9    |
+------+

此外,如果您只想将某个表加入到 id 列表中,您可以使用 LIKE 运算符。 有我的解决方案,我从博客文章 url 中获取 id 列表,将它们转换为逗号分隔的列表,以逗号开头和结尾,然后使用 LIKE 运算符通过 id 列表加入相关产品。

SELECT b2.id blog_id, b2.id_list, p.id
FROM (
    SELECT b.id,b.text,
    CONCAT(
        ",",
            REPLACE(
                EXTRACTVALUE(b.text,'//a/@id')
                , " ", ","
            )
        ,","
    ) AS id_list
    FROM blog b
) b2
LEFT JOIN production p ON b2.id_list LIKE CONCAT('%,',p.id,',%')
HAVING b2.id_list != ''

【讨论】:

    【解决方案3】:
    DELIMITER $$  
    
    CREATE PROCEDURE SPLIT_VALUE_STRING()
    
        BEGIN
    
            SET @String      = '1,22,333,444,5555,66666,777777';
            SET @Occurrences = LENGTH(@String) - LENGTH(REPLACE(@String, ',', ''));
            myloop: WHILE (@Occurrences > 0)
            DO 
                SET @myValue = SUBSTRING_INDEX(@String, ',', 1);
                IF (@myValue != '') THEN
                /* my code... */
                ELSE
                    LEAVE myloop; 
                END IF;
                SET @Occurrences = LENGTH(@String) - LENGTH(REPLACE(@String, ',', ''));
                IF (@occurrences = 0) THEN 
                    LEAVE myloop; 
                END IF;
                SET @String = SUBSTRING(@String,LENGTH(SUBSTRING_INDEX(@String, ',', 1))+2);
            END WHILE;                  
    
       END $$
    

    【讨论】:

      【解决方案4】:

      我已经这样做了,因为当您没有表值等时:

      select *
      from(
          select c, SUBSTRING_INDEX(SUBSTRING_INDEX('1|2|5|6', '|', c+1), '|', -1) as name
          from(
              SELECT (TWO_1.SeqValue + TWO_2.SeqValue + TWO_4.SeqValue + TWO_8.SeqValue + TWO_16.SeqValue + TWO_32.SeqValue) c
              FROM (
                  SELECT 0 SeqValue UNION ALL SELECT 1 SeqValue) TWO_1
                  CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 2 SeqValue) TWO_2
                  CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 4 SeqValue) TWO_4
                  CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 8 SeqValue) TWO_8
                  CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 16 SeqValue) TWO_16 
                  CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 32 SeqValue) TWO_32
          ) as b
          WHERE c <= (CHAR_LENGTH('1|2|5|6') - CHAR_LENGTH(REPLACE('1|2|5|6', '|', '')))
      ) as a;
      

      可能不是最好的答案,但可以在没有函数和过程的帮助下工作,不需要额外的表格等。

      【讨论】:

        【解决方案5】:
        select distinct
          SUBSTRING_INDEX(SUBSTRING_INDEX('1,2,3,4', ',', numbers.n), ',', -1) name
        from
          (select @rownum := @rownum + 1 as n
        from YourTable
        cross join (select @rownum := 0) r
        ) numbers 
        order by
           n
        

        【讨论】:

          【解决方案6】:

          您可以在 MySQL 中使用正则表达式来指定复杂搜索的模式,您无法解析字符串。

          但是您可以在 REPLACE 和 CONCATENATE 的帮助下构建 INSERT 查询以将数据保存到临时表。

          【讨论】:

          • 逗号分隔的字符串来自存储过程,所以最初是我需要拆分的字符串。
          【解决方案7】:

          如果您尝试拆分的文本包含多字节字符,则此方法将因 LENGTH 计算不正确而失效。对于这种情况,使用 CHAR_LENGTH 而不是 LENGTH 的以下版本可以工作:

          CREATE DEFINER=`root`@`localhost` FUNCTION `strSplit`(
                     `src` MEDIUMTEXT CHARACTER SET utf8, 
                     `delim` VARCHAR(12), 
                     `pos` INTEGER
                    )
              RETURNS mediumtext
              LANGUAGE SQL
              NOT DETERMINISTIC
              CONTAINS SQL
              SQL SECURITY DEFINER
              COMMENT ''
          BEGIN
            DECLARE output MEDIUMTEXT CHARACTER SET utf8;
            SET output = REPLACE(SUBSTRING(SUBSTRING_INDEX(src, delim, pos) ,  
                        CHAR_LENGTH(SUBSTRING_INDEX(src, delim, pos - 1)) + 1) , delim , '');
            IF output = '' THEN SET output = null; END IF;
            RETURN output;
          END
          

          参考:http://www.shakedos.com/2011/Nov/23/mysql-split-string-function-fix-split_str.html

          【讨论】:

            【解决方案8】:

            只是因为我真的很喜欢复活旧问题:

            CREATE PROCEDURE `SPLIT_LIST_STR`(IN `INISTR` TEXT CHARSET utf8mb4, IN `ENDSTR` TEXT CHARSET utf8mb4, IN `INPUTSTR` TEXT CHARSET utf8mb4, IN `SEPARATR` TEXT CHARSET utf8mb4)
            BEGIN
                SET @I = 1;
                SET @SEP = SEPARATR;
                SET @INI = INISTR;
                SET @END = ENDSTR;
                SET @VARSTR = REPLACE(REPLACE(INPUTSTR, @INI, ''), @END, '');
                SET @N = FORMAT((LENGTH(@VARSTR)-LENGTH(REPLACE(@VARSTR, @SEP, '')))/LENGTH(@SEP), 0)+1;
            
                CREATE TEMPORARY TABLE IF NOT EXISTS temp_table(P1 TEXT NULL);
            
                label1: LOOP
                    SET @TEMP = SUBSTRING_INDEX(@VARSTR, @SEP, 1);
                    insert into temp_table (`P1`) SELECT @TEMP;
                    SET @I = @I + 1;
                    SET @VARSTR = REPLACE(@VARSTR, CONCAT(@TEMP, @SEP), '');
                    IF @N >= @I THEN
                      ITERATE label1;
                    END IF;
                    LEAVE label1;
                  END LOOP label1;
                SELECT * FROM temp_table;
                END
            

            产生:

            P1
            1
            2
            3
            4
            

            当使用CALL SPLIT_LIST_STR('("', '")', '("1", "2", "3", "4")', '", "');

            我可能稍后会弹出来进一步完善代码!干杯!

            【讨论】:

              最近更新 更多