表:
UserId, Value, Date.
我想得到UserId,每个UserId的max(Date)值。也就是说,具有最新日期的每个UserId的值。有没有办法在SQL中执行此操作? (最好是Oracle)
更新:对任何含糊不清的道歉:我需要获取所有UserIds。但对于每个UserId,只有该用户具有最新日期的那一行。
答案 0 :(得分:423)
我看到很多人使用子查询或特定于供应商的功能来执行此操作,但我经常以下列方式执行此类查询而不使用子查询。它使用普通的标准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”放在分隔符中,因为它是一个SQL保留字。)
如果t1."Date" = t2."Date"
,则会出现加倍。通常表格具有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
行,并使用NULL
作为所有{的占位符{1}}列。这就是外连接的工作原理。
此查询的技巧是设计联接的匹配条件,使t2
必须与相同 t2
匹配,并且更大 { {1}}。我的想法是,如果userid
中的行存在date
更大的t2
,那么date
中与进行比较的行不能是最大的{{} 1}}表示t1
。但是如果没有匹配 - 即如果date
中的行不存在userid
而不是t2
中的行,则我们知道date
中的行是给定t1
的{{1}}行最大的行。
在这些情况下(当没有匹配时),t1
的列将为date
- 甚至是连接条件中指定的列。这就是我们使用userid
的原因,因为我们正在搜索没有找到任何行的情况,并且给定的t2
有更大的NULL
。
答案 1 :(得分:373)
这将检索my_date列值等于该userid的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中的默认窗口是从分区的第一行到当前的一行”
窗口条款仅适用于order by子句的存在。如果没有order by子句,则默认情况下不应用windowing子句,并且不能显式指定任何窗口子句。
代码有效。
答案 2 :(得分:154)
SELECT userid, MAX(value) KEEP (DENSE_RANK FIRST ORDER BY date DESC)
FROM table
GROUP BY userid
答案 3 :(得分:48)
我不知道你确切的列名,但它会是这样的:
select userid, value from users u1 where date = (select max(date) from users u2 where u1.userid = u2.userid)
答案 4 :(得分:35)
没有工作,我没有掌握Oracle,但我似乎记得Oracle允许在IN子句中匹配多个列,这至少应该避免使用相关子查询的选项,这是很少有好主意。
这样的事情,或许(不记得列列表是否应该加上括号):
SELECT *
FROM MyTable
WHERE (User, Date) IN
( SELECT User, MAX(Date) FROM MyTable GROUP BY User)
编辑:刚刚尝试过它:
SQL> create table MyTable (usr char(1), dt date);
SQL> insert into mytable values ('A','01-JAN-2009');
SQL> insert into mytable values ('B','01-JAN-2009');
SQL> insert into mytable values ('A', '31-DEC-2008');
SQL> insert into mytable values ('B', '31-DEC-2008');
SQL> select usr, dt from mytable
2 where (usr, dt) in
3 ( select usr, max(dt) from mytable group by usr)
4 /
U DT
- ---------
A 01-JAN-09
B 01-JAN-09
所以它有效,尽管其他地方提到的一些新的东西可能更有效。
答案 5 :(得分:13)
我知道您要求使用Oracle,但在SQL 2005中我们现在使用它:
-- Single Value
;WITH ByDate
AS (
SELECT UserId, Value, ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY Date DESC) RowNum
FROM UserDates
)
SELECT UserId, Value
FROM ByDate
WHERE RowNum = 1
-- Multiple values where dates match
;WITH ByDate
AS (
SELECT UserId, Value, RANK() OVER (PARTITION BY UserId ORDER BY Date DESC) Rnk
FROM UserDates
)
SELECT UserId, Value
FROM ByDate
WHERE Rnk = 1
答案 6 :(得分:6)
QUALIFY条款不是最简单也最好的吗?
select userid, my_date, ...
from users
qualify rank() over (partition by userid order by my_date desc) = 1
对于上下文,在Teradata上这里有一个不错的尺寸测试,在17秒内运行此QUALIFY版本,并在23秒内使用'内联视图'/ Aldridge解决方案#1。
答案 7 :(得分:6)
我没有Oracle来测试它,但最有效的解决方案是使用分析查询。看起来应该是这样的:
SELECT DISTINCT
UserId
, MaxValue
FROM (
SELECT UserId
, FIRST (Value) Over (
PARTITION BY UserId
ORDER BY Date DESC
) MaxValue
FROM SomeTable
)
我怀疑你可以摆脱外部查询并在内部区分,但我不确定。与此同时,我知道这个有效。
如果您想了解分析查询,我建议您阅读http://www.orafaq.com/node/55和 http://www.akadia.com/services/ora_analytic_functions.html 。以下是简短摘要。
引擎盖分析查询对整个数据集进行排序,然后按顺序处理。在处理它时,您根据特定条件对数据集进行分区,然后为每一行查看某个窗口(默认为分区中第一个到当前行的值 - 默认值也是最有效的)并且可以使用分析函数的数量(其列表与聚合函数非常相似)。
在这种情况下,这是内部查询的作用。整个数据集按UserId排序,然后按Date DESC排序。然后它一次处理它。对于每一行,您返回UserId和该UserId看到的第一个Date(因为日期是DESC排序的,即最大日期)。这为您提供了重复行的答案。然后外部DISTINCT压缩重复。
这不是分析查询的一个特别壮观的例子。要获得更大的胜利,可以考虑为每个用户和收据计算一份财务收据表,计算他们支付的总额。分析查询可以有效地解决问题。其他解决方案效率较低。这就是为什么它们是2003 SQL标准的一部分。 (不幸的是Postgres还没有它们.Grrr ......)
答案 8 :(得分:5)
在 Oracle 12c+
中,您可以使用前n 个查询以及分析函数rank
来实现这个非常简洁的而不用子查询:
select *
from your_table
order by rank() over (partition by user_id order by my_date desc)
fetch first 1 row with ties;
以上内容返回每个用户最大my_date的所有行。
如果您只想要一行包含最长日期,请将rank
替换为row_number
:
select *
from your_table
order by row_number() over (partition by user_id order by my_date desc)
fetch first 1 row with ties;
答案 9 :(得分:5)
使用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
答案 10 :(得分:4)
使用ROW_NUMBER()
为每个Date
的降序UserId
分配唯一排名,然后过滤到每个UserId
的第一行(即ROW_NUMBER
= 1)。
SELECT UserId, Value, Date
FROM (SELECT UserId, Value, Date,
ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY Date DESC) rn
FROM users) u
WHERE rn = 1;
答案 11 :(得分:3)
select VALUE from TABLE1 where TIME =
(select max(TIME) from TABLE1 where DATE=
(select max(DATE) from TABLE1 where CRITERIA=CRITERIA))
答案 12 :(得分:3)
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
答案 13 :(得分:3)
只需在工作中写一个“实时”的例子:)
这个在相同日期支持UserId的多个值。
柱: UserId,Value,Date
SELECT
DISTINCT UserId,
MAX(Date) OVER (PARTITION BY UserId ORDER BY Date DESC),
MAX(Values) OVER (PARTITION BY UserId ORDER BY Date DESC)
FROM
(
SELECT UserId, Date, SUM(Value) As Values
FROM <<table_name>>
GROUP BY UserId, Date
)
您可以使用FIRST_VALUE代替MAX,并在解释计划中查找。我没有时间玩它。
当然,如果在巨大的表格中搜索,如果在查询中使用完整提示,可能会更好。
答案 14 :(得分:2)
我参加派对的时间已经很晚,但是下面的黑客攻击会超过相关子查询和任何分析功能,但有一个限制:值必须转换为字符串。所以它适用于日期,数字和其他字符串。代码看起来不太好但执行配置文件很棒。
select
userid,
to_number(substr(max(to_char(date,'yyyymmdd') || to_char(value)), 9)) as value,
max(date) as date
from
users
group by
userid
此代码运行良好的原因是它只需要扫描一次表。它不需要任何索引,最重要的是它不需要对表进行排序,这是大多数分析功能所做的。如果您需要过滤单个用户ID的结果,索引将有所帮助。
答案 15 :(得分:2)
假设Date对于给定的UserID是唯一的,这里有一些TSQL:
SELECT
UserTest.UserID, UserTest.Value
FROM UserTest
INNER JOIN
(
SELECT UserID, MAX(Date) MaxDate
FROM UserTest
GROUP BY UserID
) Dates
ON UserTest.UserID = Dates.UserID
AND UserTest.Date = Dates.MaxDate
答案 16 :(得分:2)
我认为您应该将此变体改为先前的查询:
SELECT UserId, Value FROM Users U1 WHERE
Date = ( SELECT MAX(Date) FROM Users where UserId = U1.UserId)
答案 17 :(得分:2)
(T-SQL)首先获取所有用户及其maxdate。加入表格,在maxdates上找到用户的相应值。
create table users (userid int , value int , date datetime)
insert into users values (1, 1, '20010101')
insert into users values (1, 2, '20020101')
insert into users values (2, 1, '20010101')
insert into users values (2, 3, '20030101')
select T1.userid, T1.value, T1.date
from users T1,
(select max(date) as maxdate, userid from users group by userid) T2
where T1.userid= T2.userid and T1.date = T2.maxdate
结果:
userid value date
----------- ----------- --------------------------
2 3 2003-01-01 00:00:00.000
1 2 2002-01-01 00:00:00.000
答案 18 :(得分:2)
我觉得这样的事情。 (请原谅我任何语法错误;此时我习惯使用HQL!)
编辑:也误读了这个问题!更正了查询...SELECT UserId, Value
FROM Users AS user
WHERE Date = (
SELECT MAX(Date)
FROM Users AS maxtest
WHERE maxtest.UserId = user.UserId
)
答案 19 :(得分:2)
这里的答案仅限于Oracle。这是所有SQL中更复杂的答案:
谁拥有最佳的整体作业成绩(最多家庭作业总数)?
SELECT FIRST, LAST, SUM(POINTS) AS TOTAL
FROM STUDENTS S, RESULTS R
WHERE S.SID = R.SID AND R.CAT = 'H'
GROUP BY S.SID, FIRST, LAST
HAVING SUM(POINTS) >= ALL (SELECT SUM (POINTS)
FROM RESULTS
WHERE CAT = 'H'
GROUP BY SID)
还有一个更难的例子,需要一些解释,我没有时间atm:
提供2008年最受欢迎的书籍(ISBN和书名),即2008年最常借用的书籍。
SELECT X.ISBN, X.title, X.loans
FROM (SELECT Book.ISBN, Book.title, count(Loan.dateTimeOut) AS loans
FROM CatalogEntry Book
LEFT JOIN BookOnShelf Copy
ON Book.bookId = Copy.bookId
LEFT JOIN (SELECT * FROM Loan WHERE YEAR(Loan.dateTimeOut) = 2008) Loan
ON Copy.copyId = Loan.copyId
GROUP BY Book.title) X
HAVING loans >= ALL (SELECT count(Loan.dateTimeOut) AS loans
FROM CatalogEntry Book
LEFT JOIN BookOnShelf Copy
ON Book.bookId = Copy.bookId
LEFT JOIN (SELECT * FROM Loan WHERE YEAR(Loan.dateTimeOut) = 2008) Loan
ON Copy.copyId = Loan.copyId
GROUP BY Book.title);
希望这有助于(任何人).. :))
此致 希丁克
答案 20 :(得分:1)
如果您使用的是Postgres,则可以使用array_agg
之类的
SELECT userid,MAX(adate),(array_agg(value ORDER BY adate DESC))[1] as value
FROM YOURTABLE
GROUP BY userid
我不熟悉Oracle。这就是我想出来的
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:
答案 21 :(得分:1)
这也将处理重复项(为每个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
答案 22 :(得分:1)
刚刚测试了它,它似乎可以在日志表上运行
select ColumnNames, max(DateColumn) from log group by ColumnNames order by 1 desc
答案 23 :(得分:1)
首先尝试我误解了问题,在最佳答案之后,这是一个结果正确的完整示例:
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)
答案 24 :(得分:1)
这应该简单如下:
SELECT UserId, Value
FROM Users u
WHERE Date = (SELECT MAX(Date) FROM Users WHERE UserID = u.UserID)
答案 25 :(得分:1)
我认为这应该有用吗?
Select
T1.UserId,
(Select Top 1 T2.Value From Table T2 Where T2.UserId = T1.UserId Order By Date Desc) As 'Value'
From
Table T1
Group By
T1.UserId
Order By
T1.UserId
答案 26 :(得分:1)
select userid, value, date
from thetable t1 ,
( select t2.userid, max(t2.date) date2
from thetable t2
group by t2.userid ) t3
where t3.userid t1.userid and
t3.date2 = t1.date
恕我直言这是有效的。 HTH
答案 27 :(得分:0)
select UserId,max(Date) over (partition by UserId) value from users;
答案 28 :(得分:0)
MySQL的解决方案,没有分区KEEP,DENSE_RANK的概念。
select userid,
my_date,
...
from
(
select @sno:= case when @pid<>userid then 0
else @sno+1
end as serialnumber,
@pid:=userid,
my_Date,
...
from users order by userid, my_date
) a
where a.serialnumber=0
参考:http://benincampus.blogspot.com/2013/08/select-rows-which-have-maxmin-value-in.html
答案 29 :(得分:0)
检查this link如果您的问题看起来与该页面类似,那么我建议您使用以下查询来为该链接提供解决方案
select distinct sno,item_name,max(start_date) over(partition by sno),max(end_date) over(partition by sno),max(creation_date) over(partition by sno),
max(last_modified_date) over(partition by sno)
from uniq_select_records
order by sno,item_name asc;
将给出与该链接相关的准确结果
答案 30 :(得分:0)
使用代码:
select T.UserId,T.dt from (select UserId,max(dt)
over (partition by UserId) as dt from t_users)T where T.dt=dt;
这将检索结果,而不管UserId的重复值。 如果您的UserId是唯一的,那么它变得更加简单:
select UserId,max(dt) from t_users group by UserId;
答案 31 :(得分:0)
如果(UserID,Date)是唯一的,即同一用户没有出现两次日期,则:
select TheTable.UserID, TheTable.Value
from TheTable inner join (select UserID, max([Date]) MaxDate
from TheTable
group by UserID) UserMaxDate
on TheTable.UserID = UserMaxDate.UserID
TheTable.[Date] = UserMaxDate.MaxDate;
答案 32 :(得分:0)
SELECT a.userid,a.values1,b.mm
FROM table_name a,(SELECT userid,Max(date1)AS mm FROM table_name GROUP BY userid) b
WHERE a.userid=b.userid AND a.DATE1=b.mm;
答案 33 :(得分:0)
下面的查询可以工作:
deleteItems(at:)
答案 34 :(得分:-1)
SELECT a.*
FROM user a INNER JOIN (SELECT userid,Max(date) AS date12 FROM user1 GROUP BY userid) b
ON a.date=b.date12 AND a.userid=b.userid ORDER BY a.userid;