计算不同天数的滞后差异

时间:2017-12-08 19:24:02

标签: sql-server tsql datetime subquery lag

我需要帮助计算具有变量滞后的不同行的日期差异(特别是不在同一天的行),没有子查询,连接等。我认为这应该可以使用一些使用的内联t-SQL聚合OVER(PARTITION BY)条款,例如LAGDENSE_RANK等,但我无法完全理解它。这适用于SQL Server 2017 Developer's Edition。

一个澄清的例子:

考虑具有作业开始日期和结束日期的数据集(跨越各种项目)。有些工作在同一天开始和结束(例如工作2& 3,4和5)。我需要计算在不同日期(每个项目)开始的后续作业之间的空闲时间。这是上一个工作结束时间和当前工作开始时间之间的日子。如果之前的工作在同一天开始,那么请回顾同一项目的历史。即在同一天开始的工作可以被视为同一工作的一部分。

更新:我通过删除时间值简化了代码/输出(问题的历史记录包含原始数据集)。

IF OBJECT_ID('tempdb..#t') IS NOT NULL DROP TABLE #t; 
CREATE TABLE #t(Prj TINYINT, Beg DATE, Eñd DATE);
INSERT INTO #t SELECT 1, '1/1/17', '1/2/17';
INSERT INTO #t SELECT 1, '1/5/17', '1/7/17';
INSERT INTO #t SELECT 1, '1/5/17', '1/7/17';
INSERT INTO #t SELECT 1, '1/15/17', '1/15/17';
INSERT INTO #t SELECT 1, '1/15/17', '1/18/17';
INSERT INTO #t SELECT 1, '1/20/17', '1/24/17';
INSERT INTO #t SELECT 2, '2/2/17', '2/5/17';
INSERT INTO #t SELECT 2, '2/7/17', '2/9/17';
ALTER TABLE #t ADD Job INT NOT NULL IDENTITY (1,1) PRIMARY KEY;

LAG(.,1)函数精确使用上一个作业的结束时间,这不是我想要的。它会导致作业2& 3,4& 5.乔布斯2& 3应该使用作业1的结束时间。作业4& 5应该都使用作业3的结束时间。连接的查询正确计算空闲持续时间,但这里需要内联计算(没有连接,子查询)。

SELECT c.Job, c.Prj, c.Beg, c.Eñd, 
-- in-line computation with OVER clause
PrvEñd_lg=LAG(c.Eñd,1) OVER(PARTITION BY c.Prj ORDER BY c.Beg),
Idle_lg=DATEDIFF(DAY, LAG(c.Eñd,1) OVER(PARTITION BY c.Prj ORDER BY c.Beg), c.Beg),
-- calculation over current and (joined) previous records
PrvEñd_j=MAX(p.Eñd), 
IdleDur_j=DATEDIFF(DAY, MAX(p.Eñd), c.Beg)
FROM #t c LEFT JOIN #t p ON c.Prj=p.Prj AND c.Beg > p.Eñd
GROUP BY c.Job, c.Prj, c.Beg, c.Eñd
ORDER BY c.Prj, c.Beg


Job Prj Beg         Eñd         PrvEñd_lg   Idle_lg PrvEñd_j    IdleDur_j
1   1   2017-01-01  2017-01-02  NULL        NULL    NULL        NULL
2   1   2017-01-05  2017-01-07  2017-01-02  3       2017-01-02  3
3   1   2017-01-05  2017-01-07  2017-01-07  -2      2017-01-02  3
4   1   2017-01-15  2017-01-15  2017-01-07  8       2017-01-07  8
5   1   2017-01-15  2017-01-18  2017-01-15  0       2017-01-07  8
6   1   2017-01-20  2017-01-24  2017-01-18  2       2017-01-18  2
7   2   2017-02-02  2017-02-05  NULL        NULL    NULL        NULL
8   2   2017-02-07  2017-02-09  2017-02-05  2       2017-02-05  2

如果我可以进一步澄清任何具体细节,请告诉我。

非常感谢!

1 个答案:

答案 0 :(得分:1)

您可以使用self-join

select a.Job
, a.Prj
, a.Beg
, a.Eñd
, max(b.Eñd) as PrevEñd
, min(datediff(mi, b.Eñd, a.Beg) / (60*24.0)) as IdleDur
from #t as a
left join #t as b on a.Prj = b.Prj
                 and cast(a.Beg as date) > cast(b.Eñd as date)
group by a.Job
, a.Prj
, a.Beg
, a.Eñd

这会产生以下输出:

+-----+-----+---------------------+---------------------+---------------------+-----------+
| Job | Prj |         Beg         |         Eñd         |       PrevEñd       |  IdleDur  |
+-----+-----+---------------------+---------------------+---------------------+-----------+
|   1 |   1 | 2017-01-01 01:00:00 | 2017-01-02 02:00:00 | NULL                | NULL      |
|   2 |   1 | 2017-01-05 02:00:00 | 2017-01-07 03:00:00 | 2017-01-02 02:00:00 | 3.0000000 |
|   3 |   1 | 2017-01-05 03:00:00 | 2017-01-07 02:00:00 | 2017-01-02 02:00:00 | 3.0416666 |
|   4 |   1 | 2017-01-15 04:00:00 | 2017-01-15 03:00:00 | 2017-01-07 03:00:00 | 8.0416666 |
|   5 |   1 | 2017-01-15 15:00:00 | 2017-01-18 03:00:00 | 2017-01-07 03:00:00 | 8.5000000 |
|   6 |   1 | 2017-01-20 05:00:00 | 2017-01-24 02:00:00 | 2017-01-18 03:00:00 | 2.0833333 |
|   7 |   2 | 2017-02-02 06:00:00 | 2017-02-05 03:00:00 | NULL                | NULL      |
|   8 |   2 | 2017-02-07 07:00:00 | 2017-02-09 02:00:00 | 2017-02-05 03:00:00 | 2.1666666 |
+-----+-----+---------------------+---------------------+---------------------+-----------+