簡體   English   中英

GROUP_CONCAT 編號多列分組依據

[英]GROUP_CONCAT numbering with multiple columns group by

我有一個 GROUP_CONCAT 選擇的問題,它也應該包含類似於這個問題GROUP_CONCAT 編號的行編號,不同之處在於我必須按多列分組。

例如,我有 2 個表reviewreview_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_idcategory_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 調用中正確編號?

您應該避免在生產代碼中使用用戶定義的變量。

MySQL 5.6手冊中,它說:

作為一般規則,除了在 SET 語句中,您不應該為用戶變量賦值並在同一語句中讀取該值。

甚至在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 |
+---------------+-------------+-----------------------------------------------------------------------------------------------------------------------------------------------+

修復您的查詢。

基本問題是表本質上是未排序的,這就是 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 |

在 DB Fiddle 上查看

您需要使用兩步子查詢按審閱者編號進行排序。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM