MYSQL Group by column with 2 rows for each group

I need 2 id for each group.

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 

How to do this?

Sample Data:

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

Output Will be:

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

If you need two arbitrary ids, then use min() and 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 ;

Note: You are using a LEFT JOIN and then aggregating by a column in the second table. This is usually not a good idea, because non-matches are all placed in a NULL group. Furthermore, your WHERE clause turns the LEFT JOIN to an INNER JOIN anyway, so I've fixed that. The WHERE clause may or may not be necessary, depending on whether or not cat_name is ever NULL .

If you want the two biggest or smallest -- and can bear to have them in the same column:

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 ;

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; 

在Group-wise-max博客中进行更多讨论。


In a database that supported window functions, you could enumerate the position of each record in each group (ROW_NUMBER() OVER (PARTITION BY cat_name ORDER BY id DESC)) and then select those records in relative position 1 or 2.

In MySQL, you can mimic this by a self-join which counts the number of records whose id is greater-than-or-equal-to a record of the same cat_name (PARTITION ... ORDER BY id DESC). Record #1 in a cat_name group has only one record of >= its id , and record #N has N such records.

This query

 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;

produces:

+----+----------+
| id | cat_name |
+----+----------+
|  6 | Cat-1    |
|  4 | Cat-1    |
|  7 | Cat-2    |
|  5 | Cat-2    |
+----+----------+
链接地址: http://www.djcxy.com/p/28398.html

上一篇: 在树中查找所有最长的唯一路径

下一篇: MYSQL Group按列分组,每行2行