当我看到它时,它让我着迷,我想知道我将如何解决它。我太忙了,无法先得到答案,后来我得到了它的工作,但从那以后我就坐了几天!几天后我仍然明白我的设计,这是一个好兆头:)
我在最后添加了一些额外的数据来证明这适用于单行 JobNumber 条目,而不是假设称重总是分批进行,但结果中的第一行与原始解决方案匹配。
这种方法还使用级联 CTE(比这里接受的答案多一个,但我不会让这让我气馁!)首先是测试数据设置:
With Weighs AS -- sample data
(
SELECT 100 AS JobNumber, '01/01/2014 08:00' AS TimeOfWeigh UNION ALL
SELECT 100 AS JobNumber, '01/01/2014 09:00' AS TimeOfWeigh UNION ALL
SELECT 100 AS JobNumber, '01/01/2014 10:00' AS TimeOfWeigh UNION ALL
SELECT 200 AS JobNumber, '01/01/2014 12:00' AS TimeOfWeigh UNION ALL
SELECT 200 AS JobNumber, '01/01/2014 13:00' AS TimeOfWeigh UNION ALL
SELECT 300 AS JobNumber, '01/01/2014 15:00' AS TimeOfWeigh UNION ALL
SELECT 300 AS JobNumber, '01/01/2014 16:00' AS TimeOfWeigh UNION ALL
SELECT 100 AS JobNumber, '02/01/2014 08:00' AS TimeOfWeigh UNION ALL
SELECT 100 AS JobNumber, '02/01/2014 09:00' AS TimeOfWeigh UNION ALL
SELECT 100 AS JobNumber, '03/01/2014 10:00' AS TimeOfWeigh UNION ALL
SELECT 400 AS JobNumber, '04/01/2014 14:00' AS TimeOfWeigh UNION ALL
SELECT 300 AS JobNumber, '04/01/2014 14:30' AS TimeOfWeigh
)
,
Numbered AS -- add on a unique consecutive row number
( SELECT *, ROW_NUMBER() OVER (ORDER BY TimeOfWeigh) AS ID FROM Weighs )
,
GroupEnds AS -- add on a 1/0 flag for whether it's the first or last in a run
( SELECT *,
CASE WHEN -- next row is different JobNumber?
(SELECT ID FROM Numbered n2 WHERE n2.ID=n1.ID+1 AND n2.JobNumber=n1.JobNumber) IS NULL
THEN 1 ELSE 0 END AS GroupEnd,
CASE WHEN -- previous row is different JobNumber?
(SELECT ID FROM Numbered n2 WHERE n2.ID=n1.ID-1 AND n2.JobNumber=n1.JobNumber) IS NULL
THEN 1 ELSE 0 END AS GroupBegin
FROM Numbered n1
)
,
Begins_and_Ends AS -- make sure there are always matching pairs
( SELECT * FROM GroupEnds WHERE GroupBegin=1
UNION ALL
SELECT * FROM GroupEnds WHERE GroupEnd=1
)
,
Pairs AS -- give matching pairs the same ID number for GROUPing next..
( SELECT *, (1+Row_Number() OVER (ORDER BY ID))/2 AS PairID
FROM Begins_and_Ends
)
SELECT
Min(JobNumber) AS JobNumber,
Min(TimeOfWeigh) as [First Weigh],
Max(TimeOfWeigh) as [Last Weigh]
FROM Pairs
GROUP BY PairID
ORDER BY PairID
Numbered CTE 相当明显,为每一行提供一个有序的 ID 号。
CTE GroupEnds 添加一对布尔值 - 如果该行是 JobNumbers 运行中的第一行或最后一行,则为 1 或 0 - 通过尝试查看下一行或上一行是否是相同的 JobNumber。
从那里我只需要一种方法来配对相邻的 GroupBegins 和 GroupEnds。我使用 N-tile 排名函数 NTILE() 通过计算 GroupEnds 并将结果选择为 NTILE() 的参数将行数除以 2 来生成这些数字 - 但是当有奇数行到期时这会中断到单行批次,其中同一行是批次的开始和结束。
我通过保证相同数量的 Begin 和 End 行来解决这个问题:Begin 行和 End 行的 UNION,即使有些是相同的行。我是 CTE Begins_and_Ends。
Pairs CTE 使用 Row_Number() 除以 2 来添加对数 - 整数结果 PairID 对于行对是相同的。
这为我们提供了以下信息 - JobNumber 批次中间的所有行现在都已被过滤掉:
JOBNUMBER TIMEOFWEIGH ID End? Begin PairID
100 01/01/2014 08:00 1 0 1 1
100 01/01/2014 10:00 3 1 0 1
200 01/01/2014 12:00 4 0 1 2
200 01/01/2014 13:00 5 1 0 2
300 01/01/2014 15:00 6 0 1 3
300 01/01/2014 16:00 7 1 0 3
100 02/01/2014 08:00 8 0 1 4
100 03/01/2014 10:00 10 1 0 4
400 04/01/2014 14:00 11 1 1 5
400 04/01/2014 14:00 11 1 1 5
300 04/01/2014 14:30 12 1 1 6
300 04/01/2014 14:30 12 1 1 6
现在是最后一块蛋糕,可以通过PairID 分组并获取第一次和最后一次称重时间。我喜欢这个挑战,我想知道是否有其他人发现它在任何重量中都有用!
http://sqlfiddle.com/#!3/b4f39/48