限制在GROUP而不省略重复?

时间:2018-05-09 15:35:04

标签: mysql sql database pdo

我有这个有点复杂的查询(剥离版本):

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.titlea.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 :(得分:2)

您可以先在子查询中选择和限制组,然后将其重新连接到表中以获得最终结果。

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)

注意:是的,确实会导致本身内部的原始查询几乎重复;但这通常是这些查询最终需要的方式。

答案 1 :(得分:1)

将结果放在一个列中会有帮助吗?如果是这样,您可以使用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之前版本)中应该更难。如果满足您的需求,这是一个相对简单的解决方案。

编辑:

获得所需内容的一种方法是使用变量:

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;

答案 2 :(得分:1)

修改原始查询以获得前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子句(派生表)中的子查询,将结果限制为3组:

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

这与Uueerdo建议的相同,但使用JOIN而不是WHERE .. IN ..条件。