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

Posted

技术标签:

【中文标题】SQL Server:仅选择具有 MAX(DATE) 的行【英文标题】:SQL Server: SELECT only the rows with MAX(DATE) 【发布时间】:2011-10-30 09:31:15 【问题描述】:

我有一个数据表(数据库是 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 只返回了一行。

谢谢!

【问题讨论】:

从您的评论中选择 ROW_NUMBER() 答案。它可能看起来更长,但根据我的经验,在适当的索引下它是最快的。 感谢 Dems,感谢您的努力。 @GEMI 只是出于好奇,MAX(DATE) 不会为订单 9999 返回一行吗? 是的,但我希望每个不同的订单只返回最后一个订单行。 被***.com/questions/16550703/…和***.com/questions/18393158/…复制 【参考方案1】:

这对我来说非常好。

    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;

【讨论】:

除了缩进之外,这与 Mikael Eriksson 的回答没有任何区别。【参考方案2】:

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

select max( CONVERT(date, ReportDate)) FROM [TraxHistory]

【讨论】:

【参考方案3】:

如果你有索引 ID 和 OrderNo 你可以使用 IN:(我讨厌交易简单化,只是为了节省一些周期):

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

【讨论】:

【参考方案4】:

rownumber() over(...) 正在工作,但我不喜欢这个解决方案有两个原因。 - 当您使用 SQL2000 等旧版 SQL 时,此功能不可用 - 依赖于函数,不可读。

另一种解决方案是:

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

【讨论】:

【参考方案5】:

尽量避免IN使用JOIN

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

【讨论】:

为什么要避免IN?你有什么论据来支持你的观点吗? 执行查询需要很长时间。您可以阅读以下文章xaprb.com/blog/2006/06/28/why-large-in-clauses-are-problematic @anik 这是一篇 2006 年的文章。你最近有什么证据可以证明你在说什么吗?【参考方案6】:
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

您可能不关心这么小的样本的性能,但在大型查询中,这一切都会加起来。

【讨论】:

在我看来,这在大约 350 万行数据集上比这里的其他解决方案要快一些,但是 SSMS 建议使用一个可以将执行时间减半的索引。谢谢! 快速直接。谢谢。 我有 100k 行,对我来说 Mikael Eriksson 的查询快了 3 倍。也许是因为我在partition by子句中有ROUND函数。 如果您的日期字段具有相同的值 (04/15/2017) 用于 2 个不同的 ID,它将返回 2 行... 是的 Portekoi,这是真的,但是没有任何其他方法来区分这两行,你怎么能选择一个而不是另一个?您可以在结果上放置一个 TOP,但您怎么知道它不是您想要的另一行?【参考方案7】:

您也可以使用该选择语句作为左连接查询... 示例:

... 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 ....

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

【讨论】:

【参考方案8】:

如果您可以使用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)

【讨论】:

【参考方案9】:

如果您可以使用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      

【讨论】:

感谢 Mikael Eriksson,这是一个很棒的查询!【参考方案10】:

对于 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 @Dems 谢谢@cularis 是的,这里指的是MySql,问题没有说明是什么数据库引擎 如果您发布代码、XML 或数据示例,在文本编辑器中突出显示这些行并单击编辑器上的“代码示例”按钮 ( )工具栏以很好地格式化和语法突出显示它! 这是 MSSQL,抱歉。【参考方案11】:
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 及其最大日期。要获取表格的其他列,您可以在 OrderNoMaxDate 上加入它们。

【讨论】:

以上是关于SQL Server:仅选择具有 MAX(DATE) 的行的主要内容,如果未能解决你的问题,请参考以下文章

为啥不能为具有 date=max(date) 的最大日期的每个代码选择记录?

带 MAX 函数的内连接 - SQL SERVER-

SQL SELECT MAX() 返回多条记录

选择具有 MAX(Date) 但没有得到明显回报的记录

Sql Server:如何仅在存在时才选择列?

ORACLE SQL 按数字仅选择每组中的 MAX