LIMIT by GROUP, не пропуская дубликаты? - PullRequest
0 голосов
/ 09 мая 2018

У меня есть несколько сложный запрос (урезанная версия):

SELECT    a.item_id,
          a.title,
          a.series,
          c.title AS manufacturer_title
FROM      catalog_items AS a
JOIN      catalog_franchises AS c ON a.manufacturer_id = c.franchise_id
JOIN      catalog_franchises AS e ON a.game_id = e.franchise_id
WHERE     e.franchise_id = 6
          AND a.valid = TRUE
          AND c.valid = TRUE
          AND e.valid = TRUE
ORDER BY  c.title, a.series, a.title

Важными полями, на которых я пытаюсь сосредоточиться, являются c.title и a.series. Поэтому для краткости этот запрос возвращает:

item_id      series      manufacturer_title
46           2           fantasy flight games
63           1           gaming heads
64           1           gaming heads
33           2           reaper miniatures
124          1           triforce
125          1           triforce
45           1           triforce
43           1           usaopoly

То, что я пытаюсь сделать, это добавить LIMIT уникальную комбинацию этих полей на основе ... Если я добавлю: GROUP BY c.title, a.series, это даст мне уникальные группы:

item_id      series      manufacturer_title
46           2           fantasy flight games
63           1           gaming heads
33           2           reaper miniatures
124          1           triforce
43           1           usaopoly

Но я хочу все строки, ограниченные этими группами. Поэтому, если предел равен 3, я хочу, чтобы все элементы в первых 3 группах:

item_id      series      manufacturer_title
46           2           fantasy flight games
63           1           gaming heads
64           1           gaming heads
33           2           reaper miniatures

Надеюсь, это имеет смысл. Как я могу изменить свой запрос для достижения этого?

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

Вы можете сначала выбрать и ограничить группы в подзапросе, а затем объединить их обратно в таблицу для получения окончательных результатов.

SELECT DISTINCT a2.series, c2.title
FROM catalog_items AS a2
JOIN catalog_franchises AS c2 ON a2.manufacturer_id = c2.franchise_id
JOIN catalog_franchises AS e2 ON a2.game_id = e2.franchise_id
WHERE e2.franchise_id = 6
    AND a2.valid = TRUE
    AND c2.valid = TRUE
    AND e2.valid = TRUE
ORDER BY  c2.title, a2.series
LIMIT 3

просто добавьте это к исходному запросу WHERE:

AND (a.series, c.title) IN (query above)

Примечание. Да, это приводит к тому, что исходный запрос почти дублируется внутри самого себя; но именно так часто должны быть запросы такого типа.

0 голосов
/ 09 мая 2018

Измените исходный запрос, чтобы получить первые 3 группы:

SELECT DISTINCT c.title, a.series
FROM      catalog_items AS a
JOIN      catalog_franchises AS c ON a.manufacturer_id = c.franchise_id
JOIN      catalog_franchises AS e ON a.game_id = e.franchise_id
WHERE     e.franchise_id = 6
          AND a.valid = TRUE
          AND c.valid = TRUE
          AND e.valid = TRUE
ORDER BY  c.title, a.series
LIMIT 3

Используйте это как подзапрос в предложении FROM (производная таблица), чтобы ограничить ваш результат тремя группами:

SELECT    a.item_id,
          a.title,
          a.series,
          c.title AS manufacturer_title
FROM      catalog_items AS a
JOIN      catalog_franchises AS c ON a.manufacturer_id = c.franchise_id
JOIN      catalog_franchises AS e ON a.game_id = e.franchise_id
-- begin injected code 
JOIN (
    SELECT DISTINCT c.title, a.series
    FROM      catalog_items AS a
    JOIN      catalog_franchises AS c ON a.manufacturer_id = c.franchise_id
    JOIN      catalog_franchises AS e ON a.game_id = e.franchise_id
    WHERE     e.franchise_id = 6
              AND a.valid = TRUE
              AND c.valid = TRUE
              AND e.valid = TRUE
    ORDER BY  c.title, a.series
    LIMIT 3
) x ON a.series = x.series AND c.title = x.title
-- end injected code 
WHERE     e.franchise_id = 6
          AND a.valid = TRUE
          AND c.valid = TRUE
          AND e.valid = TRUE
ORDER BY  c.title, a.series, a.title

По сути, это то же самое, что предлагал Ууэрдо, но вместо условия WHERE .. IN .. используется JOIN.

0 голосов
/ 09 мая 2018

Поможет ли получение результатов в одном столбце? Если это так, вы можете использовать group_concat():

SELECT GROUP_CONCAT(a.item_id) as items,
       a.series, c.title AS manufacturer_title
FROM catalog_items a JOIN
     catalog_franchises c
     ON a.manufacturer_id = c.franchise_id JOIN
     catalog_franchises e
     ON a.game_id = e.franchise_id
WHERE e.franchise_id = 6 AND
      a.valid = TRUE AND
      c.valid = TRUE AND
      e.valid = TRUE
GROUP BY a.series, c.title
ORDER BY c.title, a.series;

Хотя вы можете получить результаты в отдельных строках, это сложнее, чем должно быть в MySQL (до v8). Это относительно простое решение, если оно соответствует вашим потребностям.

EDIT:

Один способ получить то, что вы хотите, использует переменные:

SELECT ist.*
FROM (SELECT ist.*,
             (@rn := if(@st = concat_ws(':', a.series, manufacturer_title), @rn,
                        if(@st := concat_ws(':', a.series, manufacturer_title), @rn + 1, @rn + 1)
                       )
             ) as rn
      FROM (SELECT a.item_id, a.series, c.title AS manufacturer_title
            FROM catalog_items a JOIN
                 catalog_franchises c
                 ON a.manufacturer_id = c.franchise_id JOIN
                 catalog_franchises e
                 ON a.game_id = e.franchise_id
            WHERE e.franchise_id = 6 AND
                  a.valid = TRUE AND
                  c.valid = TRUE AND
                  e.valid = TRUE
            ORDER BY c.title, a.series
           ) ist CROSS JOIN
           (SELECT @rn := 0, @st := '') params
      ) ist
WHERE rn <= 3;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...