在 SQL PARTITION 上选择最新项目

Posted

技术标签:

【中文标题】在 SQL PARTITION 上选择最新项目【英文标题】:Selecting latest item over a SQL PARTITION 【发布时间】:2017-09-21 18:48:20 【问题描述】:

注意:我正在尝试学习窗口函数,所以虽然我可以使用 GROUP BY 来做到这一点 - 我明确地开始使用窗口函数

我有下面的测试结果表

| Id | TargetId | TestId | ResultId | TestedOn                 |
+----+----------+--------+----------+--------------------------+
| 1  | 1        | 1      | 5        | 9/1/2017 6:28:32.220 PM  |
| 2  | 1        | 2      | 5        | 9/1/2017 6:28:32.220 PM  |
| 3  | 1        | 3      | 5        | 9/1/2017 6:28:32.220 PM  |
| 4  | 1        | 1      | 4        | 9/10/2017 6:28:32.220 PM |
| 5  | 1        | 2      | 4        | 9/10/2017 6:28:32.220 PM |
| 6  | 1        | 3      | 5        | 9/10/2017 6:28:32.220 PM |

我想为每个测试 ID 选择最新结果 - 所以我有以下内容:

SELECT DISTINCT
    TargetId,
    TestId,
    FIRST_VALUE(tr.ResultId) OVER (PARTITION BY TestId ORDER BY TestedOn DESC) LatestResultId
FROM 
    TestResult tr

我得到了预期的结果

| TargetId | TestId | LatestResultId |
+----------+--------+----------------+
| 1        | 1      | 4              |
| 1        | 2      | 4              |
| 1        | 3      | 5              |

我不明白为什么这个查询,而不是使用 FIRST_VALUE,而是使用 LAST_VALUE 并相应地进行排序,但这会产生不同的结果。

SELECT DISTINCT
    TargetId, 
    TestId,
    LAST_VALUE(tr.ResultId) OVER (PARTITION BY TestId ORDER BY TestedOn) LatestResultId
FROM  
    TestResult tr


| TargetId | TestId | LatestResultId |
+----------+--------+----------------+
| 1        | 1      | 4              |
| 1        | 1      | 5              |
| 1        | 2      | 4              |
| 1        | 2      | 5              |
| 1        | 3      | 5              |
| 1        | 3      | 5              |

对我来说,这些查询应该产生相同的结果集。

【问题讨论】:

什么是 TargetId?我在您的测试结果表中没有看到它? 糟糕,结果表中缺少它 - 在每一行中都是 1。会修复它。谢谢! 【参考方案1】:

尝试添加:

OVER (PARTITION BY TestId ORDER BY TestedOn
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)

我相信升序窗口函数的默认值是:

ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

https://docs.microsoft.com/en-us/sql/t-sql/queries/select-over-clause-transact-sql

【讨论】:

我的 SQL 版本似乎不喜欢 AND - 将查看文档 应该是ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 所以我接受它,默认情况下窗口函数只考虑前面的行,除非另有说明。谢谢!【参考方案2】:

您可以使用 with 子句来做到这一点,类似于

WITH N(TESTID,LATEST_DATE) AS

(SELECT DISTINCT TestId, Max(TestedOn ) OVER(PARTITION BY TestId) FROM TestResult)

Select TestId, ResultId from FROM TestResult TR join N ON TR.TestId = N.TESTID AND TR.TestedOn =N.LATEST_DATE

表 'N' 只是一个包含 TestID 和 LATEST_DATE 列表的临时表

【讨论】:

以上是关于在 SQL PARTITION 上选择最新项目的主要内容,如果未能解决你的问题,请参考以下文章

在一列上选择 DISTINCT,返回多个其他列(SQL Server)

2011 年的 Java:线程套接字 VS NIO:在 64 位操作系统和最新 Java 版本上选择啥?

SQL Server - 在视图上选择列的内部查询是啥

如何在 SQL 中的一个字段上选择不重复的记录?

如何在同一列上选择一些值,然后将剩余值作为 sql 中的新列

SQL - 仅在一列上选择不同的[重复]