【问题标题】:MYSQL Group by column with 2 rows for each groupMYSQL 按列分组,每组 2 行
【发布时间】:2015-08-19 10:50:35
【问题描述】:

每个组我需要 2 个id

SELECT `id`, `category`.`cat_name` 
FROM `info`
LEFT JOIN `category` ON `info`.`cat_id` = `category`.`cat_id`
WHERE `category`.`cat_name` IS NOT NULL
GROUP BY `category`.`cat_name`
ORDER BY `category`.`cat_name` ASC 

如何做到这一点?

样本数据:

id  cat_name
1   Cat-1
2   Cat-1
3   Cat-2
4   Cat-1
5   Cat-2
6   Cat-1
7   Cat-2

输出将是:

id  cat_name
6   Cat-1
4   Cat-1
7   Cat-2
5   Cat-2

【问题讨论】:

  • 请提供样本数据和预期结果。
  • SELECT GROUP_CONCAT(info.id), GROUP_CONCAT(category.id),...
  • 您想要哪“2 行”?有两排吗?具有最高 id 的两行,这似乎是您的输出显示的内容?
  • 我需要每组最新的 2 行 @RickJames
  • 您是否检查过this answer 的相关问题?

标签: mysql sql group-by greatest-n-per-group


【解决方案1】:

如果你需要两个任意的id,那么使用min()max()

SELECT c.`cat_name` , min(id), max(id)
FROM `info` i INNER JOIN
     `category` c
     ON i.`cat_id` = c.`cat_id`
WHERE c.`cat_name` IS NOT NULL
GROUP BY c`.`cat_name`
ORDER BY c.`cat_name` ASC ;

注意:您使用的是LEFT JOIN,然后按 second 表中的列进行聚合。这通常不是一个好主意,因为不匹配的都放在NULL 组中。此外,无论如何,您的WHERE 子句将LEFT JOIN 转换为INNER JOIN,所以我已经解决了这个问题。 WHERE 子句可能需要也可能不需要,这取决于 cat_name 是否曾经是 NULL

如果您想要两个最大或最小的——并且可以忍受将它们放在同一列中:

SELECT c.`cat_name`,
       substring_index(group_concat id order by id), ',', 2) as ids_2 
FROM `info` i INNER JOIN
     `category` c
     ON i.`cat_id` = c.`cat_id`
WHERE c.`cat_name` IS NOT NULL
GROUP BY c`.`cat_name`
ORDER BY c.`cat_name` ASC ;

【讨论】:

  • 感谢分享您的知识!
【解决方案2】:
SELECT  id, cat_name
    FROM  
      ( SELECT  @prev := '', @n := 0 ) init
    JOIN  
      ( SELECT  @n := if(c.cat_name != @prev, 1, @n + 1) AS n,
                @prev := c.cat_name,
                c.cat_name,
                i.id
            FROM  `info`
            LEFT JOIN  `category` ON i.`cat_id` = c.`cat_id`
            ORDER BY  c.cat_name ASC, i.id DESC 
      ) x
    WHERE  n <= 2
    ORDER BY  cat_name ASC, id DESC; 

More discussion in Group-wise-max blog.

【讨论】:

    【解决方案3】:

    在支持窗口函数的数据库中,您可以枚举每个组中每条记录的位置 (ROW_NUMBER() OVER (PARTITION BY cat_name ORDER BY id DESC)),然后在相对位置 1 或 2。

    在 MySQL 中,您可以通过自联接来模拟这一点,该自联接计算 id 大于或等于同一 cat_name 的记录的记录数(PARTITION .. . 按 id DESC 排序)。 cat_name 组中的记录 #1 只有一条 >= 其 id 的记录,记录 #NN 个这样的记录。

    这个查询

     SELECT id, cat_name
       FROM (   SELECT c.id, c.cat_name, COUNT(1) AS relative_position_in_group
                  FROM category c
             LEFT JOIN category others
                    ON c.cat_name = others.cat_name
                       AND
                       c.id <= others.id
              GROUP BY 1, 2) d
       WHERE relative_position_in_group <= 2
    ORDER BY cat_name, id DESC;
    

    产生:

    +----+----------+
    | id | cat_name |
    +----+----------+
    |  6 | Cat-1    |
    |  4 | Cat-1    |
    |  7 | Cat-2    |
    |  5 | Cat-2    |
    +----+----------+
    

    【讨论】:

      【解决方案4】:

      您的查询类似于Select id, cat_name from mytable group by cat_name,然后将其更新为Select SELECT SUBSTRING_INDEX(group_concat(id), ',', 2), cat_name from mytable group by cat_name,您将获得如下输出

      id  cat_name
      1,2   Cat-1
      3,5   Cat-2
      

      有帮助吗?

      【讨论】:

        【解决方案5】:

        您唯一需要的是在查询末尾添加limit optionordering in descending 顺序,如下所示:

        SELECT `id`, `category`.`cat_name` 
        FROM `info`
        LEFT JOIN `category` ON `info`.`cat_id` = `category`.`cat_id`
        WHERE `category`.`cat_name` IS NOT NULL
        GROUP BY `category`.`cat_name`
        ORDER BY `category`.`cat_name` DESC
        LIMIT 2 
        

        【讨论】:

        • 我认为这行不通。这会将最终结果限制为 2 个,而不是基于每个组。
        【解决方案6】:

        非常简单的按 ID 分组。是组重复数据

        【讨论】:

          【解决方案7】:

          我已经为你写了查询。希望能解决你的问题:

          SELECT 
              id, cat_name
          FROM
              (SELECT 
                  *,
                      @prevcat,
                      CASE
                          WHEN cat_name != @prevcat THEN @rownum:=0
                      END,
                      @rownum:=@rownum + 1 AS cnt,
                      @prevcat:=cat_name
              FROM
                  category
              CROSS JOIN (SELECT @rownum:=0, @prevcat:='') r
              ORDER BY cat_name ASC , id DESC) AS t
          WHERE
              t.cnt <= 2;
          

          【讨论】:

          • @Chayan,如果您认为它适合您的问题解决方案,请选择它作为答案
          【解决方案8】:

          更好地使用排名函数,下面的示例查询将有助于检查它

          select a.* from 
          (
          select a, b ,rank() over(partition by b order by a desc) as rank
          from a
          group by b,a) a
          
          where rank<=2
          

          【讨论】:

          • MySQL没有Rank函数
          【解决方案9】:

          请试试这个,它在给定的示例数据中有效

          SELECT `id`, `category`.`cat_name`
          FROM `info`
          LEFT JOIN `category` ON `info`.`cat_id` = `category`.`cat_id`
          WHERE `category`.`cat_name` IS NOT NULL and (SELECT count(*) 
          FROM info t
          WHERE t.id>=info.id and t.cat_id=category.cat_id )<3
          
          GROUP BY `category`.`cat_name`,id
          ORDER BY `category`.`cat_name` ASC
          

          【讨论】:

            【解决方案10】:

            嗯,它很丑陋,但它看起来很有效。

            select
            cat_name,
            max(id) as maxid
            from
            table1
            group by cat_name
            union all
            select
            cat_name,
            max(id) as maxid
            from
            table1
            where not exists
            (select 
              cat_name,
              maxid
              from 
              (select cat_name,max(id) as maxid from table1  group by cat_name) t
              where t.cat_name = table1.cat_name and t.maxid = table1.id)
            group by cat_name
            order by cat_name
            

            SQLFiddle

            基本上,它获取每个 cat_name 的最大值,然后将其联合到第二个查询,该查询不包括每个 cat_name 的实际最大 id,从而允许您获得每个 cat_name 的第二大 id。希望这一切都有意义...

            【讨论】:

              【解决方案11】:
              select id, cat_name from 
              
              (
               select @rank:=if(@prev_cat=cat_name,@rank+1,1) as rank,
                       id,cat_name,@prev_cat:=cat_name
              from Table1,(select @rank:=0, @prev_cat:="")t
                 order by cat_name, id desc
              ) temp
              
              where temp.rank<=2
              

              您可以在http://sqlfiddle.com/#!9/acd1b/7验证结果

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2022-01-17
                • 2012-08-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-01-31
                相关资源
                最近更新 更多