我在选择GROUP_CONCAT时遇到了问题,该行也应该包含与该问题类似的行号GROUP_CONCAT numbering 区别在于我必须按多列分组。
例如,我有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
)都有多个带有category_id
的review_detail条目(在我的示例中,只有2个类别(1,2)与查询无关)。 / p>
我必须创建一个选择,使我得到按submission_id
和category_id
分组的GROUP_CONCAT。
Concat字符串应返回
Reviewer 1: {rating}, Reviewer 2: {rating}, Reviewer 3: {rating} etc.
。
例如对于submitt_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调用中编号的方法吗?
答案 0 :(得分:1)
您应避免在生产代码中使用用户定义的变量。
作为一般规则,除了在SET语句中,永远不要 为用户变量分配一个值,并在同一变量中读取该值 声明。
甚至在documentation for 8.0中也声明:
涉及用户变量的表达式的求值顺序为 未定义。例如,不能保证
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 |
+---------------+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------+
答案 1 :(得分:1)
修复您的查询。
基本问题是表本质上是未排序的,这就是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 |
答案 2 :(得分:1)
您需要使用两步子查询来按审阅者编号排序。
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
;
答案 3 :(得分:0)
为完整起见,我还添加了解决方案,该解决方案如何在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
;
OR 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
;