SQL Server:仅选择具有MAX(DATE)的行


109

我有一个数据表(数据库是MSSQL):

    ID  OrderNO PartCode  Quantity DateEntered
    417 2144     44917    100      18-08-11
    418 7235     11762    5        18-08-11
    419 9999     60657    100      18-08-11
    420 9999     60657    90       19-08-11

我想查询一个返回OrderNO,PartCode和Quantity的查询,但仅返回最后一次注册的订单。

我想从示例表中获取以下信息:

     OrderNO PartCode  Quantity     
     2144     44917    100      
     7235     11762    5        
     9999     60657    90      

请注意,订单9999只返回了一行。

谢谢!


2
根据您的评论,选择ROW_NUMBER()答案。它可能看起来更长,但是以我的经验,使用适当的索引是最快的。
MatBailie 2011年

感谢Dems,感谢您的努力。
GEMI

1
@GEMI出于好奇,是否不MAX(DATE)为9999订单返回一行?
Zameer '16

是的,但是我希望每个不同的订单仅返回最后一个订单行。
GEMI

Answers:


184

如果rownumber() over(...)适合您....

select OrderNO,
       PartCode,
       Quantity
from (select OrderNO,
             PartCode,
             Quantity,
             row_number() over(partition by OrderNO order by DateEntered desc) as rn
      from YourTable) as T
where rn = 1      

2
谢谢Mikael Eriksson,这是一个了不起的查询!
GEMI

56

如果ROW_NUMBER()可以的话,最好的方法是Mikael Eriksson 。

其次,按照Cularis的答案加入查询。

或者,最简单直接的方法是WHERE子句中的相关子查询。

SELECT
  *
FROM
  yourTable AS [data]
WHERE
  DateEntered = (SELECT MAX(DateEntered) FROM yourTable WHERE orderNo = [data].orderNo)

要么...

WHERE
  ID = (SELECT TOP 1 ID FROM yourTable WHERE orderNo = [data].orderNo ORDER BY DateEntered DESC)

29
select OrderNo,PartCode,Quantity
from dbo.Test t1
WHERE EXISTS(SELECT 1
         FROM dbo.Test t2
         WHERE t2.OrderNo = t1.OrderNo
           AND t2.PartCode = t1.PartCode
         GROUP BY t2.OrderNo,
                  t2.PartCode
         HAVING t1.DateEntered = MAX(t2.DateEntered))

这是上面提供的所有查询中最快的。查询成本为0.0070668。

上面的首选答案由Mikael Eriksson提出,查询成本为0.0146625

您可能并不关心这么小的样本的性能,但是在大的查询中,所有这些加起来。


2
在大约350万行数据集上,这比在这里的其他解决方案要快一些,但是SSMS建议使用一个将执行时间缩短一半的索引。谢谢!
easuter 2015年

快速直接。谢谢。
斯蒂芬·曾

我有10万行,对我来说Mikael Eriksson的查询快了3倍。也许是因为我在partition by子句中有ROUND函数。
Wachburn

如果您有一个日期字段具有相同的值(04/15/2017)的2个不同ID,它将返回2行...
Portekoi

是的,Portekoi,的确如此,但是如果没有其他区分两行的方法,您如何选择一个而不是另一个?您可以在结果上放一个TOP,但是您如何知道它不是您想要的另一行呢?

10
SELECT t1.OrderNo, t1.PartCode, t1.Quantity
FROM table AS t1
INNER JOIN (SELECT OrderNo, MAX(DateEntered) AS MaxDate
            FROM table
            GROUP BY OrderNo) AS t2
ON (t1.OrderNo = t2.OrderNo AND t1.DateEntered = t2.MaxDate)

内部查询将选择所有OrderNo具有其最大日期的日期。要获取该表的其他列,您可以将它们连接到OrderNo和上MaxDate


1

对于MySql,您可以执行以下操作:

select OrderNO, PartCode, Quantity from table a
join (select ID, MAX(DateEntered) from table group by OrderNO) b on a.ID = b.ID

如果按订单号分组,则无法在内部表中选择ID
Jacob

@ Demsthank @ cularis是的,这是指MySql,问题未指定什么数据库引擎
bencobb 2011年

如果要发布代码,XML或数据示例,在文本编辑器中突出显示这些行,然后单击{ }编辑器工具栏上的“代码示例”按钮(),以很好地格式化和语法突出显示它!
marc_s

这是MSSQL,对此感到抱歉。
GEMI

1

您还可以将该select语句用作左联接查询...示例:

... left join (select OrderNO,
   PartCode,
   Quantity from (select OrderNO,
         PartCode,
         Quantity,
         row_number() over(partition by OrderNO order by DateEntered desc) as rn
  from YourTable) as T where rn = 1 ) RESULT on ....

希望这对搜索此内容的人有所帮助:)


1

rownumber()over(...)正在工作,但由于两个原因,我不喜欢此解决方案。-当您使用旧版本的SQL(例如SQL2000)时,此功能不可用。-对功能的依赖关系,并且无法真正读取。

另一个解决方案是:

SELECT tmpall.[OrderNO] ,
       tmpall.[PartCode] ,
       tmpall.[Quantity] ,
FROM   (SELECT [OrderNO],
               [PartCode],
               [Quantity],
               [DateEntered]
        FROM   you_table) AS tmpall
       INNER JOIN (SELECT [OrderNO],
                          Max([DateEntered]) AS _max_date
                   FROM   your_table
                   GROUP  BY OrderNO ) AS tmplast
               ON tmpall.[OrderNO] = tmplast.[OrderNO]
                  AND tmpall.[DateEntered] = tmplast._max_date

1

如果您已为ID和OrderNo编制了索引,则可以使用IN :(我不愿为避免混淆而简化交易,只是为了节省一些周期):

select * from myTab where ID in(select max(ID) from myTab group by OrderNo);

0

尽量避免在使用中加入

SELECT SQL_CALC_FOUND_ROWS *  FROM (SELECT  msisdn, callid, Change_color, play_file_name, date_played FROM insert_log
   WHERE play_file_name NOT IN('Prompt1','Conclusion_Prompt_1','silent')
 ORDER BY callid ASC) t1 JOIN (SELECT MAX(date_played) AS date_played FROM insert_log GROUP BY callid) t2 ON t1.date_played=t2.date_played

1
为什么要避免IN?您有任何论点支持您的观点吗?
Preza8

执行查询将需要很长时间。您可以阅读以下文章xaprb.com/blog/2006/06/28/why-large-in-clauses-are-problematic
新国王

@anik这是2006年的文章。您最近在说什么吗?
费利克斯·加侬-格雷尼尔

0

这对我来说非常好。

    select name, orderno from (
         select name, orderno, row_number() over(partition by 
           orderno order by created_date desc) as rn from orders
    ) O where rn =1;

-1

这对我有用。使用MAX(CONVERT(date,ReportDate))确保您具有日期值

select max( CONVERT(date, ReportDate)) FROM [TraxHistory]
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.