表:
UserId, Value, Date.
我想获得UserId,为每个UserId的最大值(日期)的值。也就是说,具有最新日期的每个UserId的值。有没有一种方法可以在SQL中简单地做到这一点?(最好是Oracle)
更新:为任何歧义道歉:我需要得到所有的用户id。但是对于每个UserId,只有该用户拥有最新日期的行。
表:
UserId, Value, Date.
我想获得UserId,为每个UserId的最大值(日期)的值。也就是说,具有最新日期的每个UserId的值。有没有一种方法可以在SQL中简单地做到这一点?(最好是Oracle)
更新:为任何歧义道歉:我需要得到所有的用户id。但是对于每个UserId,只有该用户拥有最新日期的行。
当前回答
Select
UserID,
Value,
Date
From
Table,
(
Select
UserID,
Max(Date) as MDate
From
Table
Group by
UserID
) as subQuery
Where
Table.UserID = subQuery.UserID and
Table.Date = subQuery.mDate
其他回答
如果你在使用Postgres,你可以使用array_agg像
SELECT userid,MAX(adate),(array_agg(value ORDER BY adate DESC))[1] as value
FROM YOURTABLE
GROUP BY userid
我不熟悉甲骨文。这是我想到的
SELECT
userid,
MAX(adate),
SUBSTR(
(LISTAGG(value, ',') WITHIN GROUP (ORDER BY adate DESC)),
0,
INSTR((LISTAGG(value, ',') WITHIN GROUP (ORDER BY adate DESC)), ',')-1
) as value
FROM YOURTABLE
GROUP BY userid
两个查询返回的结果都与接受的答案相同。看到SQLFiddles:
接受的答案 我对Postgres的解决方案 我对甲骨文的解决方案
select UserId,max(Date) over (partition by UserId) value from users;
我看到许多人使用子查询或其他窗口函数来执行此操作,但我经常以以下方式执行这种不带子查询的查询。它使用普通的标准SQL,因此它应该适用于任何品牌的RDBMS。
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON (t1.UserId = t2.UserId AND t1."Date" < t2."Date")
WHERE t2.UserId IS NULL;
换句话说:从t1中获取没有其他具有相同UserId和更大Date的行。
(我把标识符“Date”放在分隔符中,因为它是一个SQL保留字。)
如果是t1。Date = t2。“日期”,加倍出现。通常表有auto_inc(seq)键,例如id。 为避免加倍可采用以下方法:
SELECT t1.*
FROM mytable t1
LEFT OUTER JOIN mytable t2
ON t1.UserId = t2.UserId AND ((t1."Date" < t2."Date")
OR (t1."Date" = t2."Date" AND t1.id < t2.id))
WHERE t2.UserId IS NULL;
关于@Farhan的评论:
下面是更详细的解释:
外部连接尝试连接t1和t2。默认情况下,将返回t1的所有结果,如果t2中有匹配,也将返回。如果t2中t1的给定行没有匹配,那么查询仍然返回t1的行,并对t2的所有列使用NULL作为占位符。这就是外层连接的工作原理。
此查询中的技巧是设计联接的匹配条件,使t2必须匹配相同的用户id和更大的日期。它的意思是,如果t2中存在一个日期更大的行,那么t1中与它比较的行就不能是该userid的最大日期。但是如果没有匹配——也就是说,如果t2中不存在比t1中的行日期大的行——我们就知道t1中的行是给定userid中日期最大的行。
在这些情况下(当没有匹配时),t2的列将为NULL——即使是连接条件中指定的列。这就是为什么我们用WHERE t2。UserId IS NULL,因为我们正在搜索没有为给定的UserId找到日期更大的行的情况。
我想是这样的。(请原谅我的语法错误;在这一点上,我习惯使用HQL !)
编辑:也误解了问题!修正了查询…
SELECT UserId, Value
FROM Users AS user
WHERE Date = (
SELECT MAX(Date)
FROM Users AS maxtest
WHERE maxtest.UserId = user.UserId
)
SELECT userid, MAX(value) KEEP (DENSE_RANK FIRST ORDER BY date DESC)
FROM table
GROUP BY userid