ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

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

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

你用的是什么数据库? MySQL、SQL-Server、甲骨文……?
您需要最新日期的值,还是最大值和最大日期?

D
D'Arcy Rittich
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

当使用 postgresql 时,这个版本会比使用 IN(子查询)而不是内部连接更快吗?
@TheOne 根据我的经验,使用内部连接比使用条件更快
小心这种方法:如果每个用户每个日期有多个记录,它可以返回多个行(max(date) 将返回一个可以连接多个记录的日期)。为避免此问题,最好使用@dotjoe 的解决方案:stackoverflow.com/a/2411763/4406793
@RedFilter 这非常适合我的问题。非常感谢您提供这样的技术查询。顺便说一句,我使用 datetime 而不是 date 来避免在特定日期获得多个结果
为什么需要'and t.date = tm.MaxDate' 分组还不够?
a
a_horse_with_no_name

使用窗口函数(适用于 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

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

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

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

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;

实际上这仅适用于重复项,如果您有超过 2 个值,则条件 a.date < b.date 不起作用,这意味着它不是通用解决方案,尽管使用 LEFT OUTER JOIN 的想法很重要这个答案中的事情。
有趣的是,Sybase ASE 16 适用于较小的(<10k 行)表,但对于较大的表(>100k 行)它会挂起......我认为这将是关系数据库应该擅长的完美示例......
@levantpied ...是的,在较大的数据集上左连接成本很高。您可以通过将过滤条件放在连接本身上来调整性能,以便在可能的情况下以某种方式处理它。
我不明白的一件事是 IS NULL 部分:如果基于用户名 (a.username = b.username) 的表自连接,那么我们如何在结果窗口中找到 b.username 为 NULL?
@KatherineChen 对于 a 中具有最大日期的记录,b 中不会有任何更大的记录。
F
Fabian Pijcke

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

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

不存在

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 条记录。在内部查询中,我们不应该也按用户名进行匹配吗?
它适用于我使用以下内容: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,它看起来只为所有用户返回更高的条目,而不是:“一个可以为我提供每个用户的最新日期的查询”。
你确实是对的,我更新了我的查询。谢谢你的评论! @Narshe 抱歉,由于某种原因我错过了您的评论:/ 但您是绝对正确的。
这真的很好用,很简单。谢谢!
A
Alison R.

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

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

为 MySQL 工作
请注意,如果特定用户有多个具有相同日期的记录,这会给您重复。你可能想要也可能不想要这个。
这个sql在带有in子句的Oracle中很慢,它不会使用索引
H
Hugo Dozois
SELECT *     
FROM MyTable T1    
WHERE date = (
   SELECT max(date)
   FROM MyTable T2
   WHERE T1.username=T2.username
)

虽然这是另一种可能的解决方案,但这通常不是解决此问题的好方法。这样做会导致内部查询为表中的每个名称运行一次,从而导致任何显着大小的表的速度大大降低。在 where 子句中执行一个没有来自第一个查询的元素的单独查询,然后将两个表连接起来通常会更快。
这确实具有成为更易于理解的解决方案之一的一个很好的特性,它不是特定于实现的。
P
Peter Lang

这应该为您编辑的问题提供正确的结果。

子查询确保只找到最新日期的行,而外部 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

G
GrandMasterFlush
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 日都有订单怎么办?
我按用户名分组,因此它将起作用,结果将如下所示: 用户名日期值 bob 2010-02-02 1.2 brad 2010-02-02 1.4 fred 2010-01-03 1.0
J
James Moore

这类似于上面的答案之一,但在我看来,它更简单、更整洁。此外,还显示了交叉应用语句的良好用途。对于 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

i
imba22

您还可以使用分析排名函数

    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

C
Chris Catignani
SELECT MAX(DATE) AS dates 
FROM assignment  
JOIN paper_submission_detail ON  assignment.PAPER_SUB_ID = 
     paper_submission_detail.PAPER_SUB_ID 

虽然此代码可能会解决问题,但including an explanation如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的回答以添加解释并说明适用的限制和假设。 From Review
s
slartidan

如果您的数据库语法支持它,那么 TOP 1 WITH TIES 可以与 ROWNUMER 结合使用更安全。

使用您提供的示例数据,使用以下查询:

SELECT TOP 1 WITH TIES
  username, date, value
FROM user_log_in_attempts
ORDER BY ROW_NUMBER() OVER (PARTITION BY username ORDER BY date DESC)

它产生:

username | date      | value
-----------------------------
bob      | 8/4/2009  | 1.5
brad     | 2/2/2010  | 1.2
fred     | 12/2/2009 | 1.3

Demo

这个怎么运作:

ROWNUMBER() OVER (PARTITION BY... ORDER BY...) 对于每个用户名,从最年轻的 (rownumber=1) 到最旧的 (rownumber=high) 计算行列表

ORDER BY ROWNUMBER... 将每个用户的最年轻的行排序到顶部,然后是每个用户的第二年轻的行,依此类推

TOP 1 WITH TIES 因为每个用户都有一个最年轻的行,所以这些最年轻的行在排序标准的意义上是相等的(所有行数=1)。所有那些最年轻的行都将被返回。

使用 SQL-Server 测试。


但是 fred 的最新结果是 date=1/3/2010 和 value=1.0
P
Philip Kelley
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

将解决更新的问题。即使有良好的索引,它在大型表上也可能效果不佳。


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

s
skuntsel

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

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

M
Mike G
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

关于实施或解释的一两句话对于创建高质量的答案大有帮助。
D
Dheeraj Kumar

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

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


B
Bugs

我用这种方式为我桌子上的每个用户获取最后一条记录。这是根据最近在 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

F
Floern
SELECT * FROM TABEL1 WHERE DATE= (SELECT MAX(CREATED_DATE) FROM TABEL1)

欢迎使用 StackOverflow 并感谢您提供帮助。与解释解决方案的答案相比,像您这样的纯代码答案不太受欢迎。
请阅读此how-to-answer以提供高质量的答案。
和。它不会为每个用户名返回 MAX,只是返回到最新的单行。
r
resnyanskiy

我的小合集

自联接比嵌套选择更好

但是 group by 不会给你主键,这对于加入来说更可取

这个键可以通过 partition by 与 first_value (docs) 一起给出

所以,这里有一个查询:

select
 t.*
from 
 Table t inner join (
  select distinct first_value(ID) over(partition by GroupColumn order by DateColumn desc) as ID
  from Table
  where FilterColumn = 'value'
 ) j on t.ID = j.ID

优点:

使用任何列使用 where 语句过滤数据

从过滤的行中选择任何列

缺点:

从 2012 年开始需要 MS SQL Server。


H
Hardik Shah

我为我的应用程序做了一些事情,因为它:

以下是查询:

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));    

M
Matthew Jones

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

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

您的编辑只会选择一个随机的 value,而不是与 MAX(date) 行关联的那个。
它会给出最大日期,但用户名和值可能不是相同的记录。