Fetch the row which has the Max value for a column
表:
1 | UserId, VALUE, DATE. |
我想得到用户ID,每个用户ID的max(日期)值。也就是说,每个具有最新日期的用户ID的值。有没有一种简单的SQL方法可以做到这一点?(最好是Oracle)
更新:对于任何含糊不清之处道歉:我需要得到所有的用户ID。但对于每个用户ID,只有该用户具有最新日期的行。
我看到许多人使用子查询或其他特定于供应商的功能来实现这一点,但我通常使用以下方式在不使用子查询的情况下进行这种查询。它使用普通的、标准的SQL,因此它应该在任何品牌的RDBMS中工作。
1 2 3 4 5 | 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; |
换言之:从
(我将标识符"日期"放在分隔符中,因为它是SQL保留字。)
如果是
1 2 3 4 5 6 | 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回复:
下面是更详细的解释:
外部联接尝试将
这个查询的技巧是设计连接的匹配条件,使
在这些情况下(没有匹配时),
这将检索"我的日期"列值等于该用户ID的"我的日期"最大值的所有行。这可能会为用户ID检索多行,其中最大日期在多行上。
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
"分析函数Rock"
编辑:关于第一条评论…
"使用分析查询和自联接会破坏分析查询的目的"
此代码中没有自联接。相反,在包含分析函数的内联视图的结果上放置了一个谓词——这是一个非常不同的问题,完全是标准的实践。
"Oracle中的默认窗口是从分区中的第一行到当前一行。"
开窗子句仅适用于存在ORDER BY子句的情况。如果没有ORDER BY子句,则默认情况下不应用窗口化子句,并且不能显式指定任何子句。
代码有效。
1 2 3 | SELECT userid, MAX(VALUE) KEEP (DENSE_RANK FIRST ORDER BY DATE DESC) FROM TABLE GROUP BY userid |
号
我不知道您的确切列名,但应该是这样的:
1 2 3 4 5 | SELECT userid, VALUE FROM users u1 WHERE DATE = (SELECT MAX(DATE) FROM users u2 WHERE u1.userid = u2.userid) |
号
不在工作中,我没有Oracle,但我似乎记得Oracle允许在一个in子句中匹配多个列,这至少应该避免使用相关子查询的选项,这很少是一个好主意。
可能是这样(不记得列列表是否应该加括号):
1 2 3 4 | SELECT * FROM MyTable WHERE (USER, DATE) IN ( SELECT USER, MAX(DATE) FROM MyTable GROUP BY USER) |
编辑:刚刚尝试过真正的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
。
所以它是有效的,尽管其他地方提到的一些新的尖牙的东西可能会更有效。
我知道您要求使用Oracle,但在SQL 2005中,我们现在使用它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | -- 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 |
号
我没有Oracle来测试它,但是最有效的解决方案是使用分析查询。它应该是这样的:
1 2 3 4 5 6 7 8 9 10 11 | 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。这是简短的总结。
在Hood分析查询下,对整个数据集进行排序,然后按顺序进行处理。在处理数据集的过程中,您根据特定的条件对数据集进行分区,然后针对每一行查看某个窗口(默认为分区中当前行的第一个值-该默认值也是最有效的),并可以使用多个分析函数(其列表与聚合函数非常相似)计算值。
在本例中,这里是内部查询的作用。整个数据集按userid排序,然后按日期desc排序,然后一次处理。对于每一行,您返回用户ID和该用户ID看到的第一个日期(因为日期是按DESC排序的,所以这是最大日期)。这会给你一个重复行的答案。然后外部的不同挤压重复。
这不是一个特别引人注目的分析查询示例。对于一个更大的胜利,考虑取一张财务收据表,计算每个用户和收据,它们支付的总金额。分析查询可以有效地解决这一问题。其他解决方案效率较低。这就是为什么它们是2003 SQL标准的一部分。(不幸的是,Postgres还没有。GRRR…)
限定子句不是最简单也是最好的吗?
1 2 3 | SELECT userid, my_date, ... FROM users qualify rank() OVER (partition BY userid ORDER BY my_date DESC) = 1 |
就上下文而言,在Teradata上,这是一个相当大的测试,在17s和23s中使用这个限定版本运行,在23s中使用"内联视图"/Aldridge解决方案1。
使用PostgreSQL 8.4或更高版本,您可以使用:
1 2 3 4 5 | 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 |
。
在
1 2 3 4 | SELECT * FROM your_table ORDER BY rank() OVER (partition BY user_id ORDER BY my_date DESC) fetch FIRST 1 ROW WITH ties; |
。
上面返回每个用户的最大"我的"日期的所有行。
如果只需要一行的max-date,则用
1 2 3 4 | SELECT * FROM your_table ORDER BY ROW_NUMBER() OVER (partition BY user_id ORDER BY my_date DESC) fetch FIRST 1 ROW WITH ties; |
使用
1 2 3 4 5 | 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; |
。
1 2 3 | SELECT VALUE FROM TABLE1 WHERE TIME = (SELECT MAX(TIME) FROM TABLE1 WHERE DATE= (SELECT MAX(DATE) FROM TABLE1 WHERE CRITERIA=CRITERIA)) |
号
只是在工作中写了一个"现场"的例子:)
这一个支持同一日期的多个userid值。
柱:用户ID、值、日期
1 2 3 4 5 6 7 8 9 10 | 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 ) |
。
您可以使用第一个_值而不是max,并在解释计划中查找它。我没有时间玩它。
当然,如果在大型表中搜索,最好在查询中使用完整的提示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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 |
。
我参加聚会已经很晚了,但下面的黑客攻击将优于相关子查询和任何分析功能,但有一个限制:值必须转换为字符串。所以它适用于日期、数字和其他字符串。代码看起来不好,但执行概要文件很棒。
1 2 3 4 5 6 7 8 | 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筛选结果,索引将有所帮助。
(T-SQL)首先获取所有用户及其最大日期。与表联接以查找maxdates上用户的相应值。
1 2 3 4 5 6 7 8 9 10 | 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 |
结果:
1 2 3 4 | userid VALUE DATE ----------- ----------- -------------------------- 2 3 2003-01-01 00:00:00.000 1 2 2002-01-01 00:00:00.000 |
。
这里的答案只有甲骨文。以下是所有SQL中更复杂的答案:
谁的作业总成绩最好(作业分数的最大和)?
1 2 3 4 5 6 7 8 | 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) |
。
还有一个更困难的例子,需要一些解释,我没有时间自动取款机:
给出2008年最流行的书(ISBN和书名),即2008年最常借阅的书。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); |
。
希望这对(任何人)有帮助…:)
当做,古斯
我想你应该把这个变量改成前一个查询:
1 2 | SELECT UserId, VALUE FROM Users U1 WHERE DATE = ( SELECT MAX(DATE) FROM Users WHERE UserId = U1.UserId) |
。
假设日期对于给定的userid是唯一的,下面是一些tsql:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
我想是这样的。(请原谅我的语法错误;我现在已经习惯使用hql了!)
编辑:也误读了问题!已更正查询…
1 2 3 4 5 6 7 | SELECT UserId, VALUE FROM Users AS USER WHERE DATE = ( SELECT MAX(DATE) FROM Users AS maxtest WHERE maxtest.UserId = USER.UserId ) |
这还将处理重复项(为每个用户返回一行ID):
1 2 3 4 5 6 | 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 |
1 2 3 4 5 6 7 | 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 |
我知道这是怎么回事。高温高压
我觉得这应该管用?
1 2 3 4 5 6 7 8 9 | 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 |
。
这应该简单到:
1 2 3 | SELECT UserId, VALUE FROM Users u WHERE DATE = (SELECT MAX(DATE) FROM Users WHERE UserID = u.UserID) |
号
首先,我误解了这个问题,下面是一个完整的例子,有正确的结果:
1 2 3 4 5 6 7 | 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'); |
号
——
1 2 3 4 5 | SELECT id, the_value FROM TABLE_NAME u1 WHERE the_date = (SELECT MAX(the_date) FROM TABLE_NAME u2 WHERE u1.id = u2.id) |
号
——
1 2 3 4 5 6 7 | id the_value ----------- --------- 2 d 2 e 1 b (3 ROW(s) affected) |
号
如果你使用Postgres,你可以使用
1 2 3 | SELECT userid,MAX(adate),(array_agg(VALUE ORDER BY adate DESC))[1] AS VALUE FROM YOURTABLE GROUP BY userid |
号
我不熟悉甲骨文。这就是我想到的
1 2 3 4 5 6 7 8 9 10 | 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:
刚刚测试过这个,它似乎在一个记录表上工作
1 | SELECT ColumnNames, MAX(DateColumn) FROM log GROUP BY ColumnNames ORDER BY 1 DESC |
mysql的解决方案没有分区保持、密级的概念。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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
如果您的问题与该页面类似,请检查此链接,然后我建议您进行以下查询,以便为该链接提供解决方案
江户十一〔一〕号
将给出与该链接相关的准确结果
1 2 3 | 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; |
如果(userid,date)是唯一的,即同一用户没有两次出现日期,则:
1 2 3 4 5 6 | 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; |
。
1 | SELECT UserId,MAX(DATE) OVER (partition BY UserId) VALUE FROM users; |
号
使用代码:
1 2 | 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的重复值。如果您的用户ID是唯一的,那么它会变得更简单:
1 | SELECT UserId,MAX(dt) FROM t_users GROUP BY UserId; |
。
1 2 3 | 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; |