使用 OVER PARTITION BY 的问题

Posted

技术标签:

【中文标题】使用 OVER PARTITION BY 的问题【英文标题】:Problems using OVER PARTITION BY 【发布时间】:2015-08-27 08:42:45 【问题描述】:

我在使用ROW_NUMBER() OVER (PARTITION BY ...). 时遇到了一些问题

我有下表

StartTime | EndTime | ContractStart
----------+---------+--------------
10:00     |  12:00  | 2015-03-02
11:00     |  22:00  | 2014-01-02
10:00     |  12:00  | 2015-03-02
10:00     |  12:00  | 2014-01-02

此人的工作合同从2014-01-02 开始。该合同中的某些内容发生了变化,他在2015-03-02 得到了一份新合同。现在我想总结一下新合同的工作时间。我的代码是:

SELECT 
    SUM(DATEDIFF(Minute, table.StartTime, table.EndTime))
FROM
    (SELECT 
         *, 
         ROW_NUMBER() OVER (PARTITION BY ContractStart 
                            ORDER BY ContractStart DESC) AS seqnum
     FROM table) table
WHERE 
    seqnum = 1

我实际上认为代码会将表分为两个分区。每个合同的数据。现在每个分区都有一个数字。由于我设置了ORDER BY ContractStart DESC,因此最新的合约位于我在查询的Where Clause 中选择的第一个分区中。我的结果总是0,我不知道代码有什么问题。谁能说出代码有什么问题以及为什么它没有产生我想要的结果。

【问题讨论】:

提供所需的输出。 【参考方案1】:

嗯,你确实按ContractStart 对数据进行了分区,当然。但是行号实际上并没有告诉您任何有用的信息:

StartTime|EndTime|ContractStart|seqnum
10:00    |12:00  |2015-03-02   |1
11:00    |22:00  |2014-01-02   |1
10:00    |12:00  |2015-03-02   |2
10:00    |12:00  |2014-01-02   |2

您实际上并不想要一个窗口函数 - 您只需要一个简单的group by

select
 top 1
 sum(datediff(Minute, StartTime, EndTime))
from [table]
group by [ContractStart]
order by [ContractStart] desc

【讨论】:

感谢您的回答。一个问题只是为了理解。不会是 seqnum 序列 1,2,1,2 而不是 1,1,2,2? @ruedi 不。问题是,您正在按合同对行号进行分区。这意味着对于每个合同,都有一个单独的行编号 - 就好像您将一个又一个合同过滤的查询放在一起。您实际上想要完全相反 - 为与同一合同有关的所有行分配一个数字。 @ruedi 为了更清楚起见,您假设 row_number 应用于分区 - 相反,row_number 分别应用于每个分区中的数据,一个单独的序列每个分区。 哎呀。我得到了它!感谢您向我解释!【参考方案2】:

另一种方法(取决于您想要的输出)。

SELECT ContractStart, SUM(DATEDIFF(Minute, StartTime, EndTime)) AS WorkingTime
FROM yourtable
GROUP BY ContractStart

输出:

ContractStart               WorkingTime
January, 02 2014 00:00:00   780
March, 02 2015 00:00:00     240

SQL 小提琴:http://sqlfiddle.com/#!3/7d539/4/0

我还将假设这将是更大查询的一部分(包括某种员工 ID),可以包含在选择和分组依据中。

SELECT e.id, c.ContractStart, SUM(DATEDIFF(Minute, c.StartTime, c.EndTime)) AS WorkingTime
FROM contracts c
INNER JOIN employee e ON c.employeeid = e.id
GROUP BY e.id, c.ContractStart

【讨论】:

以上是关于使用 OVER PARTITION BY 的问题的主要内容,如果未能解决你的问题,请参考以下文章

ROW_NUMBER() OVER()函数用法;(分组,排序),partition by

如何在 over 函数中使用 partition by 和 order by?

使用 OVER (PARTITION BY ) 而不是 Group By

如何使用“OVER(PARTITION BY ...)”来区分[关闭]

在 OVER(PARTITION BY) 中使用 CTE

如何使用 Spark Dataframe 实现“over (partition by value)”