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


228

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

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

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

更新:我忘记了我需要具有与最新日期一致的值。


7
您正在使用哪个数据库?MySQL,SQL Server,Oracle ...
彼得·郎

1
您是否需要带有最新日期的值,或者最大值和最长时间的值?
马修·琼斯

Answers:


381
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

3
当使用postgresql时,此版本会比使用IN(子查询)而不是内部联接更快吗?
TheOne

3
@TheOne作为我的经验,使用内部联接比使用条件更快
dada

13
请谨慎使用此方法:如果每个用户有多个记录,则每个用户可以返回多行(max(date)将返回一个将多个记录连接在一起的日期)。为避免此问题,最好使用@dotjoe的解决方案:stackoverflow.com/a/2411763/4406793
Marco Roy

@RedFilter这对我的问题来说是完美的。非常感谢您的技术咨询。顺便说一下,我使用datetime而不是date来避免在特定日期获得多个结果
Muhammad Khan

为什么需要'and t.date = tm.MaxDate'分组还不够?
杜尔迪

125

使用窗口函数(可在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

1
值得说明哪个Sybase产品/版本。它不会对Sybase ASE的工作16
东升皮耶

2
这种方法的一大好处是可以保证每个分区始终只返回一行(username在本例中为),甚至不需要唯一的“可排序”字段(如加入max(date)其他答案)。
Marco Roy

1
只是在@MarcoRoy所说的内容上添加一些内容,如果您碰巧有多个具有相同最大日期的记录,则如果您更改查询(例如在调试它时),则不同的记录可能会收到行号1,因此结果可能不一致。但是,只要您真的不在乎,那么这应该不是问题。如果在日期之后添加PK,则可以解决此问题。例如:order by date desc, id desc)
Andrew

40

我看到大多数开发人员都使用内联查询,而没有考虑它对海量数据的影响。

简单地说,您可以通过以下方法实现此目的:

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;

3
实际上,这仅适用于重复项,如果您有两个以上的值,则条件a.date <b.date不起作用,这意味着这不是一般解决方案,尽管使用LEFT OUTER JOIN的想法很重要这个答案的事情。
iversoncru

有趣的是,Sybase ASE 16可以在较小的表(小于1万行)上正常工作,但是对于较大的表(大于10万行),它可以挂起...我认为这将是关系数据库应该擅长的完美示例...
levant pied

1
@levantpied ...是的,在较大的数据集上,左联接的代价很高。您可以通过在联接本身上放置过滤器条件来调整性能,以便在可能的情况下以某种方式进行处理。
sujeet

20

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

select username, date, value
from tablename where (username, date) in (
    select username, max(date) as date
    from tablename
    group by username
)

1
为MySQL工作
男生

1
请注意,如果特定用户有多个具有相同日期的记录,这将为您提供重复记录。您可能会或可能不会想要这个。
Andrew

此sql在Oracle中使用in子句的速度很慢,它将不使用索引
meadlai

9
SELECT *     
FROM MyTable T1    
WHERE date = (
   SELECT max(date)
   FROM MyTable T2
   WHERE T1.username=T2.username
)

4
尽管这是另一种可能的解决方案,但这通常不是解决此问题的好方法。以这种方式执行此操作将使内部查询针对表中的每个名称运行一次,从而导致任何规模较大的表的运行速度大大降低。进行单独的查询,该查询不包含where子句中第一个查询的元素,然后将两个表连接起来通常会更快。
Scott Chamberlain

这确实具有很好的功能,它是不是特定于实现的更易理解的解决方案之一。
Michael Szczepaniak

7

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

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

不存在

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

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

内部联接

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;

左外连接

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

我在理解NOT EXISTS版本时遇到困难。您是否在子查询部分中缺少聚合?如果我在表上运行此记录,则只能从表中拥有的40名员工中检索3条员工记录。我应该至少得到40条记录。在内部查询中,是否也应按用户名进行匹配?
Narshe

使用以下命令对我SELECT username, value FROM t WHERE NOT EXISTS ( SELECT * FROM t AS witness WHERE witness.date > t.date AND witness.username = t.username );
有用

我看了一下NOT EXISTS,它看起来只为所有用户返回较高的条目,而不是:“一个查询,它将为我提供每个用户的最新日期”。
Tasos Zervos

您确实是对的,我更新了查询。感谢您的发言!@Narshe对不起,由于某些原因,我错过了您的评论:/但是您绝对正确。
Fabian Pijcke

2

对于已编辑的问题,这应该给您正确的结果。

子查询确保仅找到最新日期的行,外部查询GROUP BY将处理联系。当同一用户有两个日期相同的条目时,它将返回最高的一个value

SELECT t.username, t.date, MAX( t.value ) value
FROM your_table t
JOIN (
       SELECT username, MAX( date ) date
       FROM your_table
       GROUP BY username
) x ON ( x.username = t.username AND x.date = t.date )
GROUP BY t.username, t.date

1

您还可以使用分析等级函数

    with temp as 
(
select username, date, RANK() over (partition by username order by date desc) as rnk from t
)
select username, rnk from t where rnk = 1

0
SELECT Username, date, value
 from MyTable mt
 inner join (select username, max(date) date
              from MyTable
              group by username) sub
  on sub.username = mt.username
   and sub.date = mt.date

将解决更新的问题。即使具有良好的索引,它在大型表上也可能无法很好地工作。


0
SELECT *
FROM ReportStatus c
inner join ( SELECT 
  MAX(Date) AS MaxDate
  FROM ReportStatus ) m
on  c.date = m.maxdate

0

对于Oracle,结果集按降序排序并获得第一条记录,因此您将获得最新记录:

select * from mytable
where rownum = 1
order by date desc

0
SELECT DISTINCT Username, Dates,value 
FROM TableName
WHERE  Dates IN (SELECT  MAX(Dates) FROM TableName GROUP BY Username)


Username    Dates       value
bob         2010-02-02  1.2       
brad        2010-01-02  1.1       
fred        2010-01-03  1.0       

如果多个用户在同一日期下了订单,这可能行不通;如果布拉德和鲍勃都在1月2日下订单怎么办?
AHiggins

我正在按用户名分组,因此它将起作用,结果将如下所示:用户名日期值bob 2010-02-02 1.2 brad 2010-02-02 1.4 fred 2010-01-03 1.0
wara

0
SELECT t1.username, t1.date, value
FROM MyTable as t1
INNER JOIN (SELECT username, MAX(date)
            FROM MyTable
            GROUP BY username) as t2 ON  t2.username = t1.username AND t2.date = t1.date

4
关于实现或解释的一两个句子在创建高质量答案方面大有帮助。

0

Select * from table1 where lastest_date=(select Max(latest_date) from table1 where user=yourUserName)

内部查询将返回当前用户的最新日期,外部查询将根据内部查询结果提取所有数据。


0

我使用这种方法来获取表上每个用户的最后一条记录。这是一个查询,以获取在PDA设备上检测到的最近时间推销员的最新位置。

CREATE FUNCTION dbo.UsersLocation()
RETURNS TABLE
AS
RETURN
Select GS.UserID, MAX(GS.UTCDateTime) 'LastDate'
From USERGPS GS
where year(GS.UTCDateTime) = YEAR(GETDATE()) 
Group By GS.UserID
GO
select  gs.UserID, sl.LastDate, gs.Latitude , gs.Longitude
        from USERGPS gs
        inner join USER s on gs.SalesManNo = s.SalesmanNo 
        inner join dbo.UsersLocation() sl on gs.UserID= sl.UserID and gs.UTCDateTime = sl.LastDate 
        order by LastDate desc

0
SELECT * FROM TABEL1 WHERE DATE= (SELECT MAX(CREATED_DATE) FROM TABEL1)

欢迎使用StackOverflow,并感谢您的帮助。与解释解决方案的答案相比,像您这样的仅代码答案不太受赞赏。
Yunnosch '17

请阅读此操作指南以提供优质的答案。
thewaywere是

和。它不会为每个用户名返回MAX,而是返回到最新的单行。
IrvineCAGuy

0

我的小编

  • 自我join比嵌套更好select
  • group by没有给你primary key哪个更适合join
  • 可以partition by结合first_valuedocs)给出此密钥

因此,这是一个查询:

选择
 吨*
从 
 表t内部联接(
  选择不同的first_value(ID)作为ID(按GroupColumn划分,按DateColumn desc划分)
  从表
  其中FilterColumn ='value'
 )j在t.ID = j.ID

优点:

  • where使用任何列使用语句过滤数据
  • select 过滤行中的任何列

缺点:

  • 从2012年开始需要MS SQL Server。

0

我为自己的应用做了一些工作:

下面是查询:

select distinct i.userId,i.statusCheck, l.userName from internetstatus 
as i inner join login as l on i.userID=l.userID 
where nowtime in((select max(nowtime) from InternetStatus group by userID));    

0

这类似于上面的答案之一,但我认为它要简单得多。同样,它显示了交叉应用语句的良好用法。对于SQL Server 2005及更高版本...

select
    a.username,
    a.date,
    a.value,
from yourtable a
cross apply (select max(date) 'maxdate' from yourtable a1 where a.username=a1.username) b
where a.date=b.maxdate

0
SELECT MAX(DATE) AS dates 
FROM assignment  
JOIN paper_submission_detail ON  assignment.PAPER_SUB_ID = 
     paper_submission_detail.PAPER_SUB_ID 

1
尽管这段代码可以解决问题,但包括解释如何以及为什么解决该问题的说明,确实可以帮助提高您的帖子质量,并可能导致更多的投票。请记住,您将来会为读者回答问题,而不仅仅是现在问的人。请编辑您的答案以添加说明,并指出适用的限制和假设。来自评论
双响


-4

您将使用聚合函数MAX和GROUP BY

SELECT username, MAX(date), value FROM tablename GROUP BY username, value

7
您的编辑将只选择一个随机的value,而不是与该MAX(date)行关联的一个。
艾莉森·R.2010年

它将给出最大日期,但用户名和值可能没有相同的记录。
SKR
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.