[英]GROUP_CONCAT numbering with multiple columns group by
我有一个 GROUP_CONCAT 选择的问题,它也应该包含类似于这个问题GROUP_CONCAT 编号的行编号,不同之处在于我必须按多列分组。
例如,我有 2 个表review
和review_detail
。
架构 (MySQL v5.5)
create table review (
`id` int(11) NOT NULL AUTO_INCREMENT,
`submission_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
create table review_detail (
`id` int(11) NOT NULL AUTO_INCREMENT,
`review_id` int(11),
`category_id` int(11),
`rating` varchar(100),
PRIMARY KEY (`id`)
);
insert into review (`id`, `submission_id`) values (1, 1), (2, 1), (3, 2), (4, 3), (5,1), (6,3), (7,2), (8,3);
insert into review_detail (`review_id`, `category_id`, `rating`)
values
(1, 1, ' submission 1.1 cat 1'), (1, 2, ' submission 1.1 cat 2'),
(2, 1, ' submission 1.2 cat 1'), (2, 2, ' submission 1.2 cat 2'),
(3, 1, ' submission 2.1 cat 1'), (3, 2, ' submission 2.1 cat 2'),
(4, 1, ' submission 3.1 cat 1'), (4, 2, ' submission 3.1 cat 1'),
(5, 1, ' submission 1.3 cat 1'), (5, 2, ' submission 1.3 cat 2'),
(6, 1, ' submission 3.2 cat 1'), (6, 2, ' submission 3.2 cat 2'),
(7, 1, ' submission 2.2 cat 1'), (7, 2, ' submission 2.2 cat 2'),
(8, 1, ' submission 3.3 cat 1'), (6, 2, ' submission 3.3 cat 2')
;
查询#1
SELECT * FROM review;
| id | submission_id |
| --- | ------------- |
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 1 |
| 6 | 3 |
| 7 | 2 |
| 8 | 3 |
查询#2
SELECT * FROM review_detail;
| id | review_id | category_id | rating |
| --- | --------- | ----------- | --------------------- |
| 1 | 1 | 1 | submission 1.1 cat 1 |
| 2 | 1 | 2 | submission 1.1 cat 2 |
| 3 | 2 | 1 | submission 1.2 cat 1 |
| 4 | 2 | 2 | submission 1.2 cat 2 |
| 5 | 3 | 1 | submission 2.1 cat 1 |
| 6 | 3 | 2 | submission 2.1 cat 2 |
| 7 | 4 | 1 | submission 3.1 cat 1 |
| 8 | 4 | 2 | submission 3.1 cat 1 |
| 9 | 5 | 1 | submission 1.3 cat 1 |
| 10 | 5 | 2 | submission 1.3 cat 2 |
| 11 | 6 | 1 | submission 3.2 cat 1 |
| 12 | 6 | 2 | submission 3.2 cat 2 |
| 13 | 7 | 1 | submission 2.2 cat 1 |
| 14 | 7 | 2 | submission 2.2 cat 2 |
| 15 | 8 | 1 | submission 3.3 cat 1 |
| 16 | 6 | 2 | submission 3.3 cat 2 |
对于提交(外键=每复习submission_id
)有多个review_detail条目category_id
(在我的例子只有2类(1,2),这是不相关的查询)。
我要创建一个选择从哪里获得通过分组的GROUP_CONCAT submission_id
和category_id
。
Concat 字符串应该返回
Reviewer 1: {rating}, Reviewer 2: {rating}, Reviewer 3: {rating} etc.
。
例如,对于 submit_id = 1 和 category_id = 1,组 concat 应该返回
Reviewer 1: submission 1.1 cat 1, Reviewer 2: submission 1.2 cat 1, Reviewer 3: submission 1.3 cat 1
。
但我无法在组 concat 中正确编号。
到目前为止,我已经进行了多次测试。
只有一个列计数器的组(作品) :
https://www.db-fiddle.com/f/6hA4Vft1mQGdw2Pew2An2T/3
Reviewer 1: submission 1.1 cat 1 of review 1 / Reviewer 2: submission 3.3 cat 1 of review 8 / Reviewer 3: submission 2.2 cat 1 of review 7 / Reviewer 4: submission 3.2 cat 1 of review 6 / ... etc.
SELECT
--review.submission_id,
review_detail.category_id,
@i,
GROUP_CONCAT(
CONCAT(
'Reviewer ',
@i := @i + 1,
': ',
rating,
' of review ', review_id
)
SEPARATOR ' / '
) concatText,
@i := 0
FROM
review_detail
LEFT JOIN review ON review.id = review_detail.review_id,
(
SELECT
@i := 0
) init
GROUP BY
review_detail.category_id
ORDER BY
review_detail.category_id ASC
;
测试 if 并与 2 个分组列的字符串进行比较(不起作用) :
https://www.db-fiddle.com/f/3woAVSw5hrav15jAmuWVdT/3
Reviewer 1: submission 1.1 cat 1 of review 1 / Reviewer 1: submission 1.2 cat 1 of review 2 / Reviewer 1: submission 1.3 cat 1 of review 5
SELECT
submission_id,
category_id,
@i,
@grp,
CONCAT_WS("-", submission_id, category_id) AS catgroup,
GROUP_CONCAT(
CONCAT(
'Reviewer ',
@i := IF(
@grp = CONCAT_WS("-", submission_id, category_id),
@i + 1,
IF(
@grp := CONCAT_WS("-", submission_id, category_id),
1,
1
)
),
': ',
rating,
' of review ', review_id
)
ORDER BY review_id, submission_id, category_id
SEPARATOR ' / '
) concatText
FROM
review_detail
LEFT JOIN review ON review.id = review_detail.review_id,
(
SELECT
@i := 0,
@grp := ''
) init
GROUP BY
review.submission_id,
review_detail.category_id
那么,当多列分组时,有没有人知道如何在 GROUP_CONCAT 调用中正确编号?
您应该避免在生产代码中使用用户定义的变量。
作为一般规则,除了在 SET 语句中,您不应该为用户变量赋值并在同一语句中读取该值。
涉及用户变量的表达式的求值顺序未定义。 例如,不能保证
SELECT @a, @a:=@a+1
首先评估@a
然后执行赋值。
在未来的版本中,这可能不再完全起作用:
以前的 MySQL 版本可以在 SET 以外的语句中为用户变量赋值。 MySQL 8.0 支持此功能以实现向后兼容性,但在未来的 MySQL 版本中可能会被删除。
所以这是一个没有用户定义变量的解决方案:
SELECT
r.submission_id,
rd.category_id,
GROUP_CONCAT(CONCAT('Reviewer ', (SELECT COUNT(*) + 1
FROM review
JOIN review_detail ON review.id = review_detail.review_id
WHERE r.submission_id = review.submission_id
AND review_detail.category_id = rd.category_id
AND review_detail.id < rd.id
), ': ', rating, ' of review ', review_id) ORDER BY rating SEPARATOR ' / ') AS shorter_column_name
FROM
review r
JOIN review_detail rd ON rd.review_id = r.id
GROUP BY r.submission_id, rd.category_id;
返回
+---------------+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| submission_id | category_id | shorter_column_name |
+---------------+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| 1 | 1 | Reviewer 1: submission 1.1 cat 1 of review 1 / Reviewer 2: submission 1.2 cat 1 of review 2 / Reviewer 3: submission 1.3 cat 1 of review 5 |
| 1 | 2 | Reviewer 1: submission 1.1 cat 2 of review 1 / Reviewer 2: submission 1.2 cat 2 of review 2 / Reviewer 3: submission 1.3 cat 2 of review 5 |
| 2 | 1 | Reviewer 1: submission 2.1 cat 1 of review 3 / Reviewer 2: submission 2.2 cat 1 of review 7 |
| 2 | 2 | Reviewer 1: submission 2.1 cat 2 of review 3 / Reviewer 2: submission 2.2 cat 2 of review 7 |
| 3 | 1 | Reviewer 1: submission 3.1 cat 1 of review 4 / Reviewer 2: submission 3.2 cat 1 of review 6 / Reviewer 3: submission 3.3 cat 1 of review 8 |
| 3 | 2 | Reviewer 1: submission 3.1 cat 1 of review 4 / Reviewer 2: submission 3.2 cat 2 of review 6 / Reviewer 3: submission 3.3 cat 2 of review 6 |
+---------------+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
修复您的查询。
基本问题是表本质上是未排序的,这就是 MySQL 优化器删除ORDER BY
。
在 MySQL 中,把所有的表放在FROM
子句中就可以用顺序做一个子查询,mysql 会保留它。
在 Mariadb 这还不够你还添加了一个LIMIT 18446744073709551615
以便优化器将保留它
架构 (MySQL v5.5)
查询#1
SELECT
submission_id,
category_id,
@i,
@grp,
CONCAT_WS("-", submission_id, category_id) AS catgroup,
GROUP_CONCAT(
CONCAT(
'Reviewer ',
@i := IF(
@grp = CONCAT_WS("-", submission_id, category_id),
@i := @i + 1,
IF(
@grp := CONCAT_WS("-", submission_id, category_id),
1,
1
)
),
': ',
rating,
' of review ', review_id
)
ORDER BY review_id, submission_id, category_id
SEPARATOR ' / '
) concatText
FROM
(SELECT review_id, submission_id, category_id,`rating` FROM review_detail
LEFT JOIN review ON review.id = review_detail.review_id
ORDER BY review_id, submission_id, category_id ) t1,
(
SELECT
@i := 0,
@grp := ''
) init
GROUP BY
submission_id,
category_id;
结果
| submission_id | category_id | @i | @grp | catgroup | concatText |
| ------------- | ----------- | --- | ---- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | 1 | 0 | | 1-1 | Reviewer 3: submission 1.1 cat 1 of review 1 / Reviewer 2: submission 1.2 cat 1 of review 2 / Reviewer 1: submission 1.3 cat 1 of review 5 |
| 1 | 2 | 3 | 1-1 | 1-2 | Reviewer 3: submission 1.1 cat 2 of review 1 / Reviewer 2: submission 1.2 cat 2 of review 2 / Reviewer 1: submission 1.3 cat 2 of review 5 |
| 2 | 1 | 3 | 1-2 | 2-1 | Reviewer 1: submission 2.1 cat 1 of review 3 / Reviewer 2: submission 2.2 cat 1 of review 7 |
| 2 | 2 | 2 | 2-1 | 2-2 | Reviewer 2: submission 2.1 cat 2 of review 3 / Reviewer 1: submission 2.2 cat 2 of review 7 |
| 3 | 1 | 2 | 2-2 | 3-1 | Reviewer 2: submission 3.1 cat 1 of review 4 / Reviewer 1: submission 3.2 cat 1 of review 6 / Reviewer 3: submission 3.3 cat 1 of review 8 |
| 3 | 2 | 3 | 3-1 | 3-2 | Reviewer 3: submission 3.1 cat 1 of review 4 / Reviewer 2: submission 3.3 cat 2 of review 6 / Reviewer 1: submission 3.2 cat 2 of review 6 |
您需要使用两步子查询按审阅者编号进行排序。
SET @i := 0;
SET @grp := '';
SELECT
submission_id,
category_id,
GROUP_CONCAT(
CONCAT(
'Reviewer ',
i,
': ',
rating,
' of review ', review_id
)
ORDER BY i
SEPARATOR ' / '
) concatText
FROM
-- second, add numbering
(
SELECT *,
@i := IF(
@grp = @grp := CONCAT_WS('-',submission_id,category_id),
@i + 1, 1) i
FROM
-- first, sort for numbering
(
SELECT
review_id,
submission_id,
category_id,
rating
FROM review_detail LEFT JOIN review ON review.id = review_detail.review_id
ORDER BY
submission_id,
category_id,
review_id
) t1
) t2
GROUP BY
submission_id,
category_id
;
为了完整起见,我还添加了如何在 Mysql 8.0 中完成此操作的解决方案
它适用于 COUNT(*)
with base as (
SELECT
review_id,
submission_id,
category_id,
rating,
count(*) over (partition by submission_id,category_id order by review_id) num
FROM review_detail LEFT JOIN review ON review.id = review_detail.review_id
ORDER BY
submission_id,
category_id,
review_id
)
select
submission_id,
category_id,
group_concat(concat('Reviewer', num, ': ', rating, ' of review ', review_id ) separator ', ') concattext
from base
group by
submission_id,
category_id
;
或 ROW_NUMBER()
with base as (
SELECT
review_id,
submission_id,
category_id,
rating,
ROW_NUMBER() over (partition by submission_id,category_id order by review_id) num
FROM review_detail
LEFT JOIN review ON review.id = review_detail.review_id
ORDER BY
submission_id,
category_id,
review_id
)
SELECT
submission_id,
category_id,
group_concat(concat('Reviewer', num, ': ', rating, ' of review ', review_id ) separator ', ') concattext
from base
group by
submission_id,
category_id
;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.