MySQL - 控制一个组返回哪一行

时间:2009-02-11 15:06:40

标签: mysql sql-order-by group-by

我有一个这样的数据库表:

id    version_id    field1    field2
1     1             texta      text1
1     2             textb      text2
2     1             textc      text3
2     2             textd      text4
2     3             texte      text5

如果你没有解决它,它包含一行的多个版本,然后是一些文本数据。

我想查询它并返回每个id的编号最大的版本。 (所以只有上面的第二行和最后一行)。

我尝试使用group by by version_id DESC进行排序 - 但它似乎在分组后进行排序,所以这不起作用。

有人有任何想法吗?我无法相信它无法完成!

更新:

想出这个,它有效,但使用子查询:

SELECT *
FROM (SELECT * FROM table ORDER BY version_id DESC) t1
GROUP BY t1.id

9 个答案:

答案 0 :(得分:49)

它被称为选择列的组最大值。 Here are several different approaches for mysql.

我将如何做到这一点:

SELECT *
FROM (SELECT id, max(version_id) as version_id FROM table GROUP BY id) t1
INNER JOIN table t2 on t2.id=t1.id and t1.version_id=t2.version_id

这将是相对有效的,尽管mysql将在内存中为子查询创建一个临时表。我假设你已经有了这个表的(id,version_id)索引。

在SQL中,您或多或少必须使用子查询来解决此类问题(semi-joins是另一个示例)。

子查询在mysql中没有得到很好的优化,但是不相关的子查询并不是那么糟糕,只要它们不是那么庞大以至于它们将被写入磁盘而不是内存。鉴于在此查询中只有两个整数,子查询在发生之前可能长达数百万行,但第一个查询中的select *子查询可能会更快地遇到此问题。

答案 1 :(得分:3)

我认为这会做到这一点,不确定它是否是最好或最快的。

SELECT * FROM table 
WHERE (id, version_id) IN 
  (SELECT id, MAX(version_id) FROM table GROUP BY id)

答案 2 :(得分:2)

SELECT id, version_id, field1, field2
FROM (
    SELECT @prev = id AS st, (@prev := id), m.*
    FROM (
           (SELECT @prev := NULL) p,
           (
            SELECT *
            FROM   mytable
            ORDER BY
                   id DESC, version_id DESC
           ) m
     ) m2
WHERE NOT IFNULL(st, FALSE);

没有子查询,UNIQUE INDEX ON MYTABLE (id, version_id)如果你有一个(我认为你应该这样做),可以传递一个

答案 3 :(得分:0)

这是伪代码,但像这样的东西应该可以正常工作

select *
from table
inner join
(
    select id , max(version_id) maxVersion
    from table 
) dvtbl ON id = dvtbl.id && versionid = dvtbl.maxVersion

答案 4 :(得分:0)

我通常使用子查询执行此操作:

从datatable中选择id,version_id,field1,field2作为dt,其中id =(从datatable中选择id,其中id = dt.id按version_id desc limit 1顺序)

答案 5 :(得分:0)

此查询将在没有组的情况下执行以下任务:

SELECT * FROM table AS t
LEFT JOIN table AS t2 
    ON t.id=t2.id 
    AND t.version_id < t2.version_id
WHERE t2.id IS NULL

它不需要任何临时表。

答案 6 :(得分:0)

一个人总是可以使用分析功能,这将给您更多的控制权

select tmp.* from ( select id,version_id,field1,field2, rank() over(partition by id order by version_id desc ) as rnk from table) tmp where tmp.rnk=1

如果根据数据类型遇到rank()函数的问题,那么也可以从row_number()或density_rank()中进行选择。

答案 7 :(得分:-1)

我认为这就是你想要的。

select id, max(v_id), field1, field2 from table group by id

我得到的结果是

  

1,2,textb,text2

     

2,3,texte,text5

修改 我重新创建了表并插入了与id相同的数据,而version_id是复合主键。这给出了我之前提供的答案。它也在MySQL中。

答案 8 :(得分:-2)

没有测试过,但这样的事情可能有用:

SELECT * FROM table GROUP BY id ORDER BY MAX(version_id)DESC