MySQL 中 GROUP_CONCAT 的对立面是啥?
Posted
技术标签:
【中文标题】MySQL 中 GROUP_CONCAT 的对立面是啥?【英文标题】:What is the opposite of GROUP_CONCAT in MySQL?MySQL 中 GROUP_CONCAT 的对立面是什么? 【发布时间】:2013-06-22 22:03:40 【问题描述】:我似乎经常遇到这个问题,我的数据格式如下:
+----+----------------------+
| id | colors |
+----+----------------------+
| 1 | Red,Green,Blue |
| 2 | Orangered,Periwinkle |
+----+----------------------+
但我希望它的格式如下:
+----+------------+
| id | colors |
+----+------------+
| 1 | Red |
| 1 | Green |
| 1 | Blue |
| 2 | Orangered |
| 2 | Periwinkle |
+----+------------+
有什么好办法吗?这种操作到底叫什么?
【问题讨论】:
那个操作叫做pivoting / unpivoting 您可以使用 FIND_IN_SET dev.mysql.com/doc/refman/8.0/en/… 您也可以在 JOIN 中组合。 【参考方案1】:您可以使用这样的查询:
SELECT
id,
SUBSTRING_INDEX(SUBSTRING_INDEX(colors, ',', n.digit+1), ',', -1) color
FROM
colors
INNER JOIN
(SELECT 0 digit UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3) n
ON LENGTH(REPLACE(colors, ',' , '')) <= LENGTH(colors)-n.digit
ORDER BY
id,
n.digit
请看小提琴here。请注意,此查询每行最多支持 4 种颜色,您应该更新您的子查询以返回 4 个以上的数字(或者您应该使用包含 10 或 100 个数字的表)。
【讨论】:
这不是我要找的东西,我更多的是寻找可以处理每个 id 的 N 行的东西。不过谢谢:) @JasonHamje 如果您需要使用查询而不是存储过程,没有其他方法:) 非常感谢。用于Here(Edit2 块)并给出归属:p @Drew 不客气!感谢您的归属! ;) 不错的答案。在一般情况下,如果结合this answer 中的技术生成长数字序列,此方法非常强大。【参考方案2】:我认为这是您所需要的(存储过程):Mysql split column string into rows
DELIMITER $$
DROP PROCEDURE IF EXISTS explode_table $$
CREATE PROCEDURE explode_table(bound VARCHAR(255))
BEGIN
DECLARE id INT DEFAULT 0;
DECLARE value TEXT;
DECLARE occurance INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE splitted_value INT;
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT table1.id, table1.value
FROM table1
WHERE table1.value != '';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TEMPORARY TABLE IF EXISTS table2;
CREATE TEMPORARY TABLE table2(
`id` INT NOT NULL,
`value` VARCHAR(255) NOT NULL
) ENGINE=Memory;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO id, value;
IF done THEN
LEAVE read_loop;
END IF;
SET occurance = (SELECT LENGTH(value)
- LENGTH(REPLACE(value, bound, ''))
+1);
SET i=1;
WHILE i <= occurance DO
SET splitted_value =
(SELECT REPLACE(SUBSTRING(SUBSTRING_INDEX(value, bound, i),
LENGTH(SUBSTRING_INDEX(value, bound, i - 1)) + 1), ',', ''));
INSERT INTO table2 VALUES (id, splitted_value);
SET i = i + 1;
END WHILE;
END LOOP;
SELECT * FROM table2;
CLOSE cur1;
END; $$
【讨论】:
太棒了,这正是我想要的 @kmas,“库存程序”是什么意思?bound
参数有什么作用? (编辑):看起来它充当要替换的分隔符。 REPLACE(str, find_string, replace_with)
=> REPLACE(value, bound, '')
【参考方案3】:
这为我节省了很多时间!更进一步:在一个典型的实现中,很可能会有一个表,它根据标识键 color_list
枚举颜色。无需修改查询即可将新颜色添加到实现中,并且可以通过将查询更改为以下内容来完全避免可能无穷无尽的union
-clause:
SELECT id,
SUBSTRING_INDEX(SUBSTRING_INDEX(colors, ',', n.digit+1), ',', -1) color
FROM
colors
INNER JOIN
(select id as digit from color_list) n
ON LENGTH(REPLACE(colors, ',' , '')) <= LENGTH(colors)-n.digit
ORDER BY id, n.digit;
但是,表 color_list 中的 Id 保持顺序很重要。
【讨论】:
【参考方案4】:不需要存储过程。一个 CTE 就足够了:
CREATE TABLE colors(id INT,colors TEXT);
INSERT INTO colors VALUES (1, 'Red,Green,Blue'), (2, 'Orangered,Periwinkle');
WITH RECURSIVE
unwound AS (
SELECT *
FROM colors
UNION ALL
SELECT id, regexp_replace(colors, '^[^,]*,', '') colors
FROM unwound
WHERE colors LIKE '%,%'
)
SELECT id, regexp_replace(colors, ',.*', '') colors
FROM unwound
ORDER BY id
;
+------+------------+
| id | colors |
+------+------------+
| 1 | Red |
| 1 | Green |
| 1 | Blue |
| 2 | Orangered |
| 2 | Periwinkle |
+------+------------+
【讨论】:
如果这个存在于 2013 年就好了!非常酷。我不再经常使用 MySQL,但如果我这样做了,我一定会记得检查一下。 @JasonHamje 这不是 MySQL/MariaDB 特定的。相同的代码适用于 PostgreSQL。如果加载一个扩展来添加函数regexp_replace
,它也可以在SQLite上运行。【参考方案5】:
注意这可以在不创建临时表的情况下完成
select id, substring_index(substring_index(genre, ',', n), ',', -1) as genre
from my_table
join
(SELECT @row := @row + 1 as n FROM
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t,
(SELECT @row:=0) r) as numbers
on char_length(genre)
- char_length(replace(genre, ',', '')) >= n - 1
【讨论】:
如果你愿意,也可以添加计数和分组 在 select 语句中读取和写入相同的用户变量是未定义的行为。请参阅 MySQL 手册重新用户变量和分配。【参考方案6】:如果分隔符是数据的一部分,但被双引号嵌入,那么我们如何分割它。
示例 第一个,“第二个,s”,第三个
它应该是 第一的 第二,s 第三个
【讨论】:
看这个有点晚了..但是为什么不使用替换删除引号然后按照答案说的做呢?以上是关于MySQL 中 GROUP_CONCAT 的对立面是啥?的主要内容,如果未能解决你的问题,请参考以下文章
MYSQL中group_concat有长度限制!默认1024