【问题标题】:Join multiple mysql tables and group by加入多个mysql表并分组
【发布时间】:2019-07-27 04:15:44
【问题描述】:

我有这些表:

颜色

colorId colorName
1       Blu
2       Green
3       Yellow
4       Red

colors_groups

colorsGroupId  colorsGroupName
1              BG    
2              BY
3              RB       

colors_groups_ids

colorsGroupId colorId  colorOrder
1             1        1
1             2        2
2             1        1
2             2        3
3             4        1
3             1        2

书籍封面

bookId       colorsGroupId
1            1
1            2
2            2

是否有可能得到这样的结果:

bookId       colorsGroupIds    colorsGroupName
1            1,2               BG (Blu/Green), BY (Blu/Yellow) 
2            2                 BY (Blu/Yellow)

我尝试使用 group_by 的两个视图,而加入第一个视图的第二个视图非常慢。 任何帮助将不胜感激。


编辑。我尝试了你的观点而不是我的观点,但是 SELECT 很慢,mysql 解释这样的查询:

id  select_type     table               type    possible_keys   key             key_len     ref             rows    Extra   
1   PRIMARY         <derived2>          ALL     NULL            NULL            NULL        NULL            3320    
2   DERIVED         colors_groups       ALL     NULL            NULL            NULL        NULL            3320    Using filesort
2   DERIVED         colors_groups_ids   ref     colorsgroupid   colorsgroupid   3           colorsgroupid   1   
2   DERIVED         colors              eq_ref  PRIMARY         PRIMARY         2           colors.colorId  1       Using where

3220 是 color_groups 记录的数量。为什么要使用文件排序,每 3320 条记录获取两次?

这是查询:

SELECT
   groups.colorsGroupId, groups.colorsGroupName, 
   GROUP_CONCAT(groups_ids.colorId ORDER BY groups_ids.order ASC) AS colors_ids,
   GROUP_CONCAT(colors.colorName ORDER BY groups_ids.order ASC SEPARATOR "/") AS colors_names,
   CONCAT(groups.colorsGroupName, " (", GROUP_CONCAT(colors.colorName ORDER BY groups_ids.order ASC SEPARATOR "/"), ")") AS colors_names_complete,
   FROM colors_groups AS groups
   JOIN colors_groups_ids group_ids
   ON groups.colorsGroupId=group_ids.colorsGroupId
   JOIN colors
   ON group_ids.colorId=colors.colorId
   GROUP BY groups.colorsGroupId, groups.colorsGroupName

【问题讨论】:

  • I tried 我们能看到吗?
  • 我在尝试您的观点后编辑了答案
  • 提示:不要将其保存为视图 - 你说“而不是”,但目前,您似乎没有查询
  • 谢谢。保存为视图变化很大吗?
  • 另外,一个 EXPLAIN 非常有用,不需要为所有相关表提供 SHOW CREATE TABLE 语句

标签: mysql join view group-by


【解决方案1】:

我用这些观点“解决”了:

colors_groups_view

SELECT
colors_groups.colorsGroupId,
colors_groups.colorsGroupName,
colors_groups_ids.colorId,
colors_groups_ids.order,
colors.colorName 
FROM colors_groups 
LEFT JOIN colors_groups_ids ON colors_groups_ids.colorGroupId=colors_groups.colorGroupId
LEFT JOIN colors ON colors_groups.colorId=colors.colorId

这个视图给出的结果如下:

colorsGroupId    colorsGroupName   colorId    order    colorName
1                BG                1          1        Blue
1                BG                2          2        Green
2                BY                1          1        Blue
2                BY                3          2        Yellow

然后:

books_view

SELECT 
books.bookId,
(
    SELECT
    GROUP_CONCAT(
        (
            SELECT 
            CONCAT(colors_groups_view.colorsGroupName, " (", GROUP_CONCAT(colors_groups_view.colorName ORDER BY colors_groups_view.order ASC SEPARATOR "/"), ")", "") AS booksGroupsNames 
            FROM colors_groups_view
            WHERE colors_groups_view.colorsGroupId=books_covers.colorsGroupId 
            GROUP BY colors_groups_view.colorsGroupId
        ) 
        SEPARATOR ", "
    )
    FROM books_covers 
    WHERE books_covers.bookId=books.bookId
    GROUP BY books_covers.bookId
) AS booksGroupsNames
FROM books 

由于第一个没有 GROUP_BY 任何内容,因此速度非常快。我不知道这是否可以避免,是否所有事情都可以在一个查询中完成。

【讨论】:

    【解决方案2】:

    请注意,MySQL 在使用视图方面非常糟糕,所以在我看来,它们没有任何用处。

    请考虑以下几点:

    DROP TABLE IF EXISTS colors;
    
    CREATE TABLE colors
    (colorId SERIAL PRIMARY KEY
    ,colorName VARCHAR(12) NOT NULL UNIQUE
    );
    
    INSERT INTO colors VALUES
    (11,'Blu'),
    (12,'Green'),
    (13,'Yellow'),
    (14,'Red');
    
    DROP TABLE IF EXISTS color_groups;
    
    CREATE TABLE color_groups
    (colorsGroupId SERIAL PRIMARY KEY
    ,colorsGroupName CHAR(2) NOT NULL UNIQUE
    );
    
    INSERT INTO color_groups VALUES
    (101,'BG'),
    (102,'BY'),
    (103,'RB');       
    
    DROP TABLE IF EXISTS colors_groups_ids;
    
    CREATE TABLE colors_groups_ids
    (colorsGroupId INT NOT NULL
    ,colorId INT NOT NULL
    ,colorOrder INT NOT NULL
    ,PRIMARY KEY(colorsGroupId,colorid)
    );
    
    INSERT INTO colors_groups_ids VALUES
    (101,11,1),
    (101,12,2),
    (102,11,1),
    (102,13,2), -- note: fixed the error in the original data set
    (103,14,1),
    (103,11,2);
    
    DROP TABLE IF EXISTS book_covers;
    
    CREATE TABLE book_covers
    (bookId INT NOT NULL
    ,colorsGroupId INT NOT NULL
    ,PRIMARY KEY(bookid,colorsgroupid)
    );
    
    INSERT INTO book_covers VALUES
    (1001,101),
    (1001,102),
    (1002,102);
    
    SELECT b.bookid
         , GROUP_CONCAT(DISTINCT x.colorsgroupid ORDER BY x.colorsgroupid) colorsgroupids
         , GROUP_CONCAT(DISTINCT x.colorsgroupname ORDER BY x.x.colorsgroupid) colorgroupname
      FROM book_covers b
      JOIN 
         ( SELECT g.colorsgroupid
                , CONCAT(g.colorsgroupname,' (',GROUP_CONCAT(c.colorname ORDER BY gc.colororder SEPARATOR '/' ),')') colorsgroupname 
             FROM color_groups g
             JOIN colors_groups_ids gc
               ON gc.colorsgroupid = g.colorsgroupid
             JOIN colors c
               ON c.colorid = gc.colorid
            GROUP
               BY g.colorsgroupid
                , g.colorsgroupname
         ) x
        ON x.colorsgroupid = b.colorsgroupid
      GROUP
         BY b.bookid;
    +--------+----------------+--------------------------------+
    | bookid | colorsgroupids | colorgroupname                 |
    +--------+----------------+--------------------------------+
    |   1001 | 101,102        | BG (Blu/Green),BY (Blu/Yellow) |
    |   1002 | 102            | BY (Blu/Yellow)                |
    +--------+----------------+--------------------------------+
    

    最后,可以看出,这个查询使用了 CONCAT 和 GROUP_CONCAT。但是,除非使用其他一些聚合函数(SUM/MAX/AVG),否则我认为最好在应用程序代码中处理这种事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-28
      • 1970-01-01
      • 2023-03-14
      • 2012-05-28
      相关资源
      最近更新 更多