如何查询sql以获取每个用户的最新记录日期

fis*_*ead 189 sql greatest-n-per-group

我有一个表,它是用户登录时的集合条目.

username, date,      value
--------------------------
brad,     1/2/2010,  1.1
fred,     1/3/2010,  1.0
bob,      8/4/2009,  1.5
brad,     2/2/2010,  1.2
fred,     12/2/2009, 1.3

etc..
Run Code Online (Sandbox Code Playgroud)

如何创建一个可以为每个用户提供最新日期的查询?

更新:我忘了我需要一个与最新日期一致的值.

Red*_*ter 324

select t.username, t.date, t.value
from MyTable t
inner join (
    select username, max(date) as MaxDate
    from MyTable
    group by username
) tm on t.username = tm.username and t.date = tm.MaxDate
Run Code Online (Sandbox Code Playgroud)

  • 谨慎使用这种方法:如果每个用户有多个记录,则每个用户可以返回多行(“ max(date)”将返回将多个记录连接在一起的日期)。为避免此问题,最好使用@dotjoe的解决方案:/sf/answers/168823441/。 (7认同)
  • 使用postgresql时,这个版本会比使用IN(子查询)而不是内连接更快吗? (3认同)
  • @TheOne作为我的经验,使用内连接比在条件下更快 (3认同)
  • @RedFilter 这非常适合我的问题。非常感谢您提出这样的技术询问。顺便说一句,我使用日期时间而不是日期来避免获得特定日期的多个结果 (2认同)

dot*_*joe 98

使用窗口函数(适用于Oracle,Postgres 8.4,SQL Server 2005,DB2,Sybase,Firebird 3.0,MariaDB 10.3)

select * from (
    select
        username,
        date,
        value,
        row_number() over(partition by username order by date desc) as rn
    from
        yourtable
) t
where t.rn = 1
Run Code Online (Sandbox Code Playgroud)

  • 这种方法的一大好处是保证每个分区始终只返回一行(在这种情况下为`username`),甚至不需要唯一的“可订购”字段(例如在`max(date)`上加入)在其他答案中)。 (6认同)
  • 只是为了添加一些内容到 @MarcoRoy 所说的内容,如果您碰巧有多个具有相同最大日期的记录,如果您更改查询,就像在调试它时一样,不同的记录可能会收到行号 1,所以结果可能不一致。但只要你真的不在乎,那么这应该不是问题。如果您在日期之后添加 PK,则可以解决此问题。例如:“按日期 desc、id desc) 排序”。 (3认同)
  • 值得澄清的 Sybase 产品/版本。它不适用于 Sybase ASE 16。 (2认同)

小智 38

我看到大多数开发人员使用内联查询而不考虑它对大数据的影响.

简单地说,您可以通过以下方式实现

SELECT a.username, a.date, a.value
FROM myTable a
LEFT OUTER JOIN myTable b
ON a.username = b.username 
AND a.date < b.date
WHERE b.username IS NULL
ORDER BY a.date desc;
Run Code Online (Sandbox Code Playgroud)

  • 实际上,这仅适用于重复项,如果您有两个以上的值,则条件a.date &lt;b.date不起作用,这意味着这不是一般的解决方案,尽管使用LEFT OUTER JOIN的想法很重要这个答案中的东西。 (3认同)

Fab*_*cke 22

根据我的经验,最快的方法是获取表中没有更新行的每一行。

另一个优点是使用的语法非常简单,并且查询的含义很容易掌握(获取所有行,以便所考虑的用户名不存在较新的行)。

不存在

SELECT username, value
FROM t
WHERE NOT EXISTS (
  SELECT *
  FROM t AS witness
  WHERE witness.username = t.username AND witness.date > t.date
);
Run Code Online (Sandbox Code Playgroud)

ROW_NUMBER

SELECT username, value
FROM (
  SELECT username, value, row_number() OVER (PARTITION BY username ORDER BY date DESC) AS rn
  FROM t
) t2
WHERE rn = 1
Run Code Online (Sandbox Code Playgroud)

内部联接

SELECT t.username, t.value
FROM t
INNER JOIN (
  SELECT username, MAX(date) AS date
  FROM t
  GROUP BY username
) tm ON t.username = tm.username AND t.date = tm.date;
Run Code Online (Sandbox Code Playgroud)

左外连接

SELECT username, value
FROM t
LEFT OUTER JOIN t AS w ON t.username = w.username AND t.date < w.date
WHERE w.username IS NULL
Run Code Online (Sandbox Code Playgroud)


Ali*_* R. 20

要获取包含用户最大日期的整行:

select username, date, value
from tablename where (username, date) in (
    select username, max(date) as date
    from tablename
    group by username
)
Run Code Online (Sandbox Code Playgroud)

  • 这适用于Oracle,但不适用于SQL Server. (4认同)
  • 为 MySQL 工作 (2认同)
  • 请注意,如果特定用户有多个具有相同日期的记录,这将给您重复。你可能想要也可能不想要这个。 (2认同)

小智 7

SELECT *     
FROM MyTable T1    
WHERE date = (
   SELECT max(date)
   FROM MyTable T2
   WHERE T1.username=T2.username
)
Run Code Online (Sandbox Code Playgroud)

  • 虽然这是另一种可能的解决方案,但这通常不是解决此问题的好方法.这样做会导致内部查询对表中的每个名称运行一次,导致任何有效大小的表的主要减速.执行一个单独的查询,该查询没有来自where子句中第一个查询的元素,然后将两个表连接起来*通常*会更快. (4认同)