【问题标题】:select top N records for each entity为每个实体选择前 N 条记录
【发布时间】:2016-06-24 06:58:03
【问题描述】:

我有一个table,如下所示 -


ID   |  Reported Date                  | Device_ID
-------------------------------------------
1    | 2016-03-09 09:08:32.827         | 1
2    | 2016-03-08 09:08:32.827         | 1
3    | 2016-03-08 09:08:32.827         | 1
4    | 2016-03-10 09:08:32.827         | 2
5    | 2016-03-05 09:08:32.827         | 2

现在,我想要一个基于date columntop 1 row 用于每个device_ID

预期输出


ID   |  Reported Date                  | Device_ID
-------------------------------------------
1    | 2016-03-09 09:08:32.827         | 1
4    | 2016-03-10 09:08:32.827         | 2

我正在使用SQL Server 2008 R2。我可以去写Stored Procedure 来处理它,但我想用简单的查询来做。

****************编辑******************************

“Felix Pamittan”的回答效果很好,但“N”只需将其更改为

SELECT
    Id, [Reported Date], Device_ID
FROM (
    SELECT *,
        Rn = ROW_NUMBER() OVER(PARTITION BY Device_ID ORDER BY [ReportedDate] DESC)
    FROM tbl
)t
WHERE Rn >= N

他在评论中提到了这一点,想把它添加到问题中,这样没有人会错过它。

【问题讨论】:

  • 你可以使用Group ByMAX来得到你想要的

标签: sql sql-server sql-server-2008-r2 database-administration


【解决方案1】:

使用ROW_NUMBER:

SELECT
    Id, [Reported Date], Device_ID
FROM (
    SELECT *,
        Rn = ROW_NUMBER() OVER(PARTITION BY Device_ID ORDER BY [ReportedDate] DESC)
    FROM tbl
)t
WHERE Rn = 1

【讨论】:

  • 为什么不使用Group ByMAX。有什么特别的原因吗?
  • @CoderofCode 因为OP需要Id
  • @AnshulNigam 你需要在子查询上加上别名,否则会产生语法错误。
  • “t”被视为派生表。
  • @FelixPamittan:所以如果我想获得前 5 名,应该在最后替换 Rn = 5 吗?
【解决方案2】:

您也可以尝试使用 CTE

With DeviceCTE AS
(SELECT *, ROW_NUMBER() OVER(PARTITION BY Device_ID ORDER BY [Reported Date] DESC) AS Num
 FROM tblname)
 SELECT Id, [Reported Date], Device_ID
 From DeviceCTE
 Where Num = 1

【讨论】:

    【解决方案3】:

    如果您不能使用分析函数,例如因为您的应用层不允许这样做,所以您可以尝试以下使用子查询来获得答案的解决方案:

    SELECT t1.ID, t2.maxDate, t1.Device_ID
    INNER JOIN
    (
        SELECT Device_ID, MAX([Reported Date]) AS maxDate
        FROM yourTable
        GROUP BY Device_ID
    ) t2
        ON t1.Device_ID = t2.Device_ID AND t1.[Reported Date] = t2.maxDate
    

    【讨论】:

      【解决方案4】:
      Select * from DEVICE_TABLE D 
      where [Reported Date] = (Select Max([Reported Date]) from DEVICE_TABLE where Device_ID = D.Device_ID)
      

      应该做到这一点,假设“基于日期列的前 1 行”意味着您要选择每个 Device_ID 的最新报告日期?

      对于你的标题,选择每个 Device_ID 的前 5 行

      Select * from DEVICE_TABLE D 
      where [Reported Date] in (Select top 5 [Reported Date] from DEVICE_TABLE D  where Device_ID =  D.Device_ID)
      order by Device_ID, [Reported Date] desc
      

      将为您提供每个设备 ID 的前 5 个最新报告。 如果您的数据不按顺序排列,您可能需要整理出前 5 个日期...

      【讨论】:

        【解决方案5】:

        同样没有分析功能,您可以使用 CROSS APPLY :

        DECLARE @tbl TABLE(Id INT,[Reported Date] DateTime , Device_ID INT)
         
        INSERT INTO @tbl
        VALUES 
        (1,'2016-03-09 09:08:32.827',1),
        (2,'2016-03-08 09:08:32.827',1),
        (3,'2016-03-08 09:08:32.827',1),
        (4,'2016-03-10 09:08:32.827',2),
        (5,'2016-03-05 09:08:32.827',2)
        
        
        SELECT r.*
        FROM ( SELECT DISTINCT Device_ID FROM @tbl ) d
            CROSS APPLY ( SELECT TOP 1 * 
                          FROM @tbl t 
                          WHERE d.Device_ID = t.Device_ID ) r
        

        可以轻松修改以支持 N 条记录。

        感谢 wBob 回答这个问题here

        【讨论】:

          猜你喜欢
          • 2019-01-17
          • 1970-01-01
          • 2015-03-23
          • 2020-06-14
          • 2010-09-15
          • 2011-03-22
          • 2012-12-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多