获取具有列最大值的行

时间:2020-03-06 14:36:10  来源:igfitidea点击:

桌子:

UserId, Value, Date.

我想获取UserId,每个UserId的max(Date)的值。即,具有最新日期的每个UserId的值。有没有一种方法可以简单地在SQL中做到这一点? (最好是Oracle)

更新:对于任何歧义,我们深表歉意:我需要获取所有UserIds。但是对于每个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, value
      from users u1
     where date = (select max(date)
                     from users u2
                    where u1.userid = u2.userid)

(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

这将检索其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中的默认窗口是从分区的第一行到当前窗口"

windowing子句仅在order by子句存在的情况下适用。如果没有order by子句,则默认情况下不应用任何窗口子句,并且不能显式指定任何子句。

该代码有效。

如果(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;

我将shuold设为先前查询的变体:

SELECT UserId, Value FROM Users U1 WHERE 
Date = ( SELECT MAX(Date)    FROM Users where UserId = U1.UserId)

假定日期对于给定的用户ID是唯一的,下面是一些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

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

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

恕我直言,这有效。高温超导

我认为这应该工作吗?

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

这应该很简单:

SELECT UserId, Value
FROM Users u
WHERE Date = (SELECT MAX(Date) FROM Users WHERE UserID = u.UserID)

首先尝试我误解了问题,然后再回答最重要的问题,这是一个完整的示例,其结果正确:

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)

SELECT userid, MAX(value) KEEP (DENSE_RANK FIRST ORDER BY date DESC)
  FROM table
  GROUP BY userid

我知道我们要求使用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

我没有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看到的第一个日期(因为日期按DESC排序,因此是最大日期)。这为我们提供了重复行的答案。然后,外部DISTINCT壁球重复。

这不是解析查询的特别引人注目的示例。要获得更大的胜利,可以考虑制作一张财务收据表,并为每个用户和收据计算他们所支付的总金额。分析查询可以有效地解决这一问题。其他解决方案效率较低。这就是为什么它们成为2003 SQL标准的一部分。 (不幸的是Postgres还没有它们。Grrr...)

我看到很多人使用子查询或者其他供应商特定的功能来执行此操作,但是我经常以以下方式在没有子查询的情况下进行这种查询。它使用普通的标准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. " 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作为t2所有列的占位符。这就是外部联接通常的工作方式。

此查询的诀窍是设计联接的匹配条件,以使t2必须匹配相同的用户ID和更大的日期。这样的想法是,如果t2中存在行且日期较大,则与其进行比较的t1中的行就不能成为该用户ID的最大日期。但是如果没有匹配项-即如果t2中不存在日期比t1中的日期大的行-我们知道t1中的行是给定用户ID的日期最大的行。

在这些情况下(当没有匹配项时),t2的列将为NULL-甚至连接条件中指定的列。这就是为什么我们使用" WHERE t2.UserId IS NULL"的原因,因为我们正在搜索找不到给定userid的行具有较大日期的情况。

没有工作,我没有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

这样就可以了,尽管其他地方提到的一些新事物可能更有效。

这还将处理重复项(每个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

答案只有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);

希望这对我们有所帮助(任何人).. :)

问候,
古斯

刚刚测试过,它似乎可以在日志表上工作

select ColumnNames, max(DateColumn) from log  group by ColumnNames order by 1 desc

只需在工作中写一个"实时"示例即可:)

该日期在同一日期支持UserId的多个值。

列:
用户名,值,日期

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并在说明计划中查找它。我没有时间玩。

当然,如果要搜索巨大的表,最好在查询中使用FULL提示。