Присоединяйтесь к нескольким таблицам MySQL и группируйте по - PullRequest
0 голосов
/ 05 марта 2019

У меня есть эти таблицы:

цвет

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

books_covers

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 - номер записи группы цветов. Почему он использует сортировку файлов и получает каждые 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

Ответы [ 2 ]

0 голосов
/ 06 марта 2019

Я "решил" с этими представлениями:

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, это очень быстро.Я не знаю, можно ли этого избежать и можно ли сделать все за один запрос.

0 голосов
/ 05 марта 2019

Обратите внимание, что 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), я думаю, что лучше обрабатывать подобные вещи в коде приложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...