61

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

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 编号最大的版本。(因此仅在上面的第二行和最后一行)。

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

有人有什么想法吗?我就不信做不到!

更新:

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

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

9 回答 9

56

这称为选择列的分组最大值。以下是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 的一个不足之处在于,您或多或少必须对此类问题使用子查询(半连接是另一个示例)。

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

于 2009-02-11T15:09:42.627 回答
4

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

SELECT * FROM table 
WHERE (id, version_id) IN 
  (SELECT id, MAX(version_id) FROM table GROUP BY id)
于 2009-02-11T15:09:54.607 回答
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)没有子查询,如果你有一个就传递一个(我认为你应该这样做)

于 2009-02-11T15:29:28.693 回答
1

此查询将通过以下方式在没有组的情况下完成工作:

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

它不需要任何临时表。

于 2012-07-23T08:48:06.147 回答
0

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

select *
from table
inner join
(
    select id , max(version_id) maxVersion
    from table 
) dvtbl ON id = dvtbl.id && versionid = dvtbl.maxVersion
于 2009-02-11T15:10:15.183 回答
0

我通常使用子查询来做到这一点:

select id, version_id, field1, field2 from datatable as dt where id = (select id from datatable where id = dt.id order by version_id desc limit 1)

于 2009-02-11T15:10:52.343 回答
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() 或 dense_rank() 中进行选择。

于 2018-07-30T13:31:22.747 回答
-1

我想这就是你想要的。

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

我从中得到的结果是

1、2、文本b、文本2

2, 3, texte, text5

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

于 2009-02-11T15:18:30.530 回答
-3

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

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

于 2009-05-08T23:13:06.233 回答