объединение многих таблиц в 1 запрос, что приводит к дублированию

125
13

У меня есть таблица под названием "игры".

В игре могут быть несколько тегов и несколько авторов. Каждый тег или автор может принадлежать к нескольким играм.

Я хочу отслеживать каждый отдельный тег и каждый отдельный автор с отдельными таблицами, поэтому у меня есть следующие таблицы и их столбцы:

игры: id,... game_tags: id, name game_tags_map: id, game_id, tag_id game_authors: id, name game_authors_map: id, game_id, author_id

Если я хочу получить запись игры со всеми ее тегами, я выполняю следующий запрос:

SELECT g.*,
GROUP_CONCAT(gt.name) as tag_names, GROUP_CONCAT(gt.id) as tag_ids
FROM games g
INNER JOIN game_tags_map gtm ON g.id = gtm.game_id
INNER JOIN game_tags gt ON gtm.tag_id = gt.id
WHERE g.id = 1
GROUP BY g.id

И я получаю:

id ... category_names    category_ids
1 ... 3D,2 Player 2,1

Именно так, как я хочу. Однако, что я могу выполнить, чтобы получить author_names и author_ids? Я попробую:

SELECT g.id,
GROUP_CONCAT(gt.name) as tag_names, GROUP_CONCAT(gt.id) as tag_ids,
GROUP_CONCAT(ga.name) as author_names, GROUP_CONCAT(ga.id) as author_ids
FROM games g
INNER JOIN game_tags_map gtm ON g.id = gtm.game_id
INNER JOIN game_tags gt ON gtm.tag_id = gt.id
INNER JOIN game_authors_map gam ON g.id = gam.game_id
INNER JOIN game_authors ga ON gam.author_id = ga.id
WHERE g.id = 1
GROUP BY g.id

Но я понимаю:

id ... category_names           category_ids      author_names          author_ids
1 ... 3D,2 Player,3D,2 Player 2,1,2,1 Tom,Dave,Tom,Dave 1,2,1,2

Другими словами, все удваивается. Также я замечаю, что это занимает почти в 10 раз дольше, чем я ожидал. Первый запрос занял 0,001 с, второй - 0,008 с.

Что я делаю не так?

спросил(а) 2021-01-25T17:05:53+03:00 4 месяца, 3 недели назад
1
Решение
108

Самое простое решение - использовать на GROUP_CONCAT различие:

SELECT
g.id,
GROUP_CONCAT(DISTINCT gt.name) as tag_names,
GROUP_CONCAT(DISTINCT gt.id) as tag_ids,
GROUP_CONCAT(DISTINCT ga.name) as author_names,
GROUP_CONCAT(ga.id) as author_ids
FROM ....

другим решением является использование GROUP_CONCAT в подзапросе, что-то вроде этого:

SELECT
g.id,
tag_names,
author_names,
...
FROM
games g INNER JOIN (SELECT id, GROUP_CONCAT(...) AS tag_names
FROM ...
GROUP BY id) t
ON g.id=t.id
INNER JOIN (SELECT id, GROUP_CONCAT(...) AS author_names
FROM ...
GROUP BY id) a
ON g.id = a.id

ответил(а) 2021-01-25T17:05:53+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема