代码之家  ›  专栏  ›  技术社区  ›  mister martin

按组限制而不忽略重复项?

  •  0
  • mister martin  · 技术社区  · 6 年前

    我有一个有点复杂的查询(精简版):

    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 回复  |  直到 6 年前
        1
  •  2
  •   Uueerdo    6 年前

    您可以先选择并限制子查询中的组,然后将其连接回表以获得最终结果。

    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
    

    只需将其添加到原始查询的位置:

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

    注意:是的,is本身几乎会导致重复原始查询;但这往往是这些类型的查询最终需要的。

        2
  •  1
  •   Paul Spiegel    6 年前

    修改原始查询以获取前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建议的基本相同,但使用联接而不是 WHERE .. IN .. 条件

        3
  •  1
  •   Gordon Linoff    6 年前

    在一列中获得结果会有帮助吗?如果是,您可以使用 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;