MYSQL按列分组,每组有2行

时间:2015-08-19 10:50:35

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

每组我需要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

11 个答案:

答案 0 :(得分:3)

如果您需要两个任意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,然后按第二个表中的列进行聚合。这通常不是一个好主意,因为非匹配都放在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 ;

答案 1 :(得分:0)

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

答案 2 :(得分:0)

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

在MySQL中,您可以通过自联接来模仿这一点,该自联接计算id大于或等于同一cat_name的记录的记录数( PARTITION ...按ID DESC排序)。 cat_name组中的记录#1只有一个&gt; = id的记录,记录# N N 这样的记录。< / p>

此查询

 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    |
+----+----------+

答案 3 :(得分:0)

您的查询与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

有帮助吗?

答案 4 :(得分:0)

您唯一需要的是在查询末尾添加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 

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

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;

答案 7 :(得分:0)

最好使用排名功能,下面的输出示例查询将有助于检查

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

答案 8 :(得分:0)

请尝试这个,它适用于给出的样本数据

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

答案 9 :(得分:0)

嗯,这很难看,但它看起来很有效。

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。希望所有这些都有意义......

答案 10 :(得分:0)

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

验证结果