表:
UserId, Value, Date.
我想获得UserId,为每个UserId的最大值(日期)的值。也就是说,具有最新日期的每个UserId的值。有没有一种方法可以在SQL中简单地做到这一点?(最好是Oracle)
更新:为任何歧义道歉:我需要得到所有的用户id。但是对于每个UserId,只有该用户拥有最新日期的行。
表:
UserId, Value, Date.
我想获得UserId,为每个UserId的最大值(日期)的值。也就是说,具有最新日期的每个UserId的值。有没有一种方法可以在SQL中简单地做到这一点?(最好是Oracle)
更新:为任何歧义道歉:我需要得到所有的用户id。但是对于每个UserId,只有该用户拥有最新日期的行。
当前回答
我没有Oracle来测试它,但最有效的解决方案是使用分析查询。它应该看起来像这样:
SELECT DISTINCT
UserId
, MaxValue
FROM (
SELECT UserId
, FIRST (Value) Over (
PARTITION BY UserId
ORDER BY Date DESC
) MaxValue
FROM SomeTable
)
我怀疑您可以摆脱外部查询,并在内部放置distinct,但我不确定。与此同时,我知道这招管用。
如果您想了解分析查询,我建议您阅读http://www.orafaq.com/node/55和http://www.akadia.com/services/ora_analytic_functions.html。这是一个简短的总结。
在底层,分析查询对整个数据集进行排序,然后按顺序进行处理。当你处理它的时候,你根据特定的标准对数据集进行分区,然后对每一行查看一些窗口(默认为当前行分区中的第一个值-默认也是最有效的),并可以使用许多分析函数(其列表非常类似于聚合函数)计算值。
在本例中,下面是内部查询的功能。整个数据集先按UserId排序,再按Date DESC排序,然后一次处理。对于每一行,您返回UserId和该UserId看到的第一个日期(因为日期是按DESC排序的,所以这是最大日期)。这就得到了重复行的答案。然后外部的DISTINCT压缩重复项。
这并不是一个特别引人注目的分析查询示例。如果想获得更大的胜利,可以考虑制作一张财务收据表格,计算每个用户和收据的总花费。分析查询可以有效地解决这个问题。其他解决方案效率较低。这就是为什么它们是2003 SQL标准的一部分。(不幸的是Postgres还没有。叽阿…)
其他回答
首先,我看错了问题,下面是一个完整的例子,结果是正确的:
CREATE TABLE table_name (id int, the_value varchar(2), the_date datetime);
INSERT INTO table_name (id,the_value,the_date) VALUES(1 ,'a','1/1/2000');
INSERT INTO table_name (id,the_value,the_date) VALUES(1 ,'b','2/2/2002');
INSERT INTO table_name (id,the_value,the_date) VALUES(2 ,'c','1/1/2000');
INSERT INTO table_name (id,the_value,the_date) VALUES(2 ,'d','3/3/2003');
INSERT INTO table_name (id,the_value,the_date) VALUES(2 ,'e','3/3/2003');
--
select id, the_value
from table_name u1
where the_date = (select max(the_date)
from table_name u2
where u1.id = u2.id)
--
id the_value
----------- ---------
2 d
2 e
1 b
(3 row(s) affected)
这也会处理重复的数据(为每个user_id返回一行):
SELECT *
FROM (
SELECT u.*, FIRST_VALUE(u.rowid) OVER(PARTITION BY u.user_id ORDER BY u.date DESC) AS last_rowid
FROM users u
) u2
WHERE u2.rowid = u2.last_rowid
这将检索my_date列值等于该用户id的my_date最大值的所有行。这可能会为最大日期位于多行上的用户id检索多行。
select userid,
my_date,
...
from
(
select userid,
my_date,
...
max(my_date) over (partition by userid) max_my_date
from users
)
where my_date = max_my_date
“解析函数摇滚”
编辑:关于第一条评论……
“使用分析查询和自连接违背了分析查询的目的”
这段代码中没有自连接。相反,在包含分析函数的内联视图的结果上放置了一个谓词——这是非常不同的事情,完全是标准的实践。
Oracle的默认窗口是从分区的第一行到当前一行
加窗条款仅适用于存在按顺序条款的情况。如果没有按子句排序,默认情况下就不会应用任何窗口子句,也不能显式地指定任何窗口子句。
代码可以工作。
我没有Oracle来测试它,但最有效的解决方案是使用分析查询。它应该看起来像这样:
SELECT DISTINCT
UserId
, MaxValue
FROM (
SELECT UserId
, FIRST (Value) Over (
PARTITION BY UserId
ORDER BY Date DESC
) MaxValue
FROM SomeTable
)
我怀疑您可以摆脱外部查询,并在内部放置distinct,但我不确定。与此同时,我知道这招管用。
如果您想了解分析查询,我建议您阅读http://www.orafaq.com/node/55和http://www.akadia.com/services/ora_analytic_functions.html。这是一个简短的总结。
在底层,分析查询对整个数据集进行排序,然后按顺序进行处理。当你处理它的时候,你根据特定的标准对数据集进行分区,然后对每一行查看一些窗口(默认为当前行分区中的第一个值-默认也是最有效的),并可以使用许多分析函数(其列表非常类似于聚合函数)计算值。
在本例中,下面是内部查询的功能。整个数据集先按UserId排序,再按Date DESC排序,然后一次处理。对于每一行,您返回UserId和该UserId看到的第一个日期(因为日期是按DESC排序的,所以这是最大日期)。这就得到了重复行的答案。然后外部的DISTINCT压缩重复项。
这并不是一个特别引人注目的分析查询示例。如果想获得更大的胜利,可以考虑制作一张财务收据表格,计算每个用户和收据的总花费。分析查询可以有效地解决这个问题。其他解决方案效率较低。这就是为什么它们是2003 SQL标准的一部分。(不幸的是Postgres还没有。叽阿…)
在PostgreSQL 8.4或更高版本中,你可以这样使用:
select user_id, user_value_1, user_value_2
from (select user_id, user_value_1, user_value_2, row_number()
over (partition by user_id order by user_date desc)
from users) as r
where r.row_number=1