我们有一张包含以下数据的表
Id,ItemId,SeqNumber;DateTimeTrx
1,100,254,2011-12-01 09:00:00
2,100,1,2011-12-01 09:10:00
3,200,7,2011-12-02 11:00:00
4,200,5,2011-12-02 10:00:00
5,100,255,2011-12-01 09:05:00
6,200,3,2011-12-02 09:00:00
7,300,0,2011-12-03 10:00:00
8,300,255,2011-12-03 11:00:00
9,300,1,2011-12-03 10:30:00
Id是一个标识列。 ItemId的序列从0开始,一直到255,然后重置为0.所有这些信息都存储在一个名为Item的表中。序列号的顺序由DateTimeTrx确定,但是这样的数据可以随时进入系统。预期输出如下所示 -
ItemId,PrevorNext,SeqNumber,DateTimeTrx,MissingNumber
100,Previous,255,2011-12-01 09:05:00,0
100,Next,1,2011-12-01 09:10:00,0
200,Previous,3,2011-12-02 09:00:00,4
200,Next,5,2011-12-02 10:00:00,4
200,Previous,5,2011-12-02 10:00:00,6
200,Next,7,2011-12-02 11:00:00,6
300,Previous,1,2011-12-03 10:30:00,2
300,Next,255,2011-12-03 16:30:00,2
我们需要在缺失序列之前和之后获取这些行。在ItemId 300的上述示例中 - 序列1的记录首先输入(2011-12-03 10:30:00)然后输入255(2011-12-03 16:30:00),因此这里缺少的数字是2.所以1是先前的,255是下一个,2是第一个缺失的数字。来到ItemId 100,序列255的记录首先进入(2011-12-02 09:05:00)然后进入1(2011-12-02 09:10:00),因此255先前然后是1,因此0是第一个缺失的数字。
在上述预期结果中,MissingNumber列是第一个出现缺失的数字,仅用于说明该示例。
我们不会遇到一次完整系列重置的情况,即它可以是一个从255到0的系列纲要,如同itemid 100或0到255,如ItemId 300.因此我们需要按升序(0,1,... 255)或降序(254,254,0,2)等识别序列缺失。
我们如何在t-sql中实现这一目标?
答案 0 :(得分:1)
可以像这样工作:
;WITH b AS (
SELECT *
,row_number() OVER (ORDER BY ItemId, DateTimeTrx, SeqNumber) AS rn
FROM tbl
), x AS (
SELECT
b.Id
,b.ItemId AS prev_Itm
,b.SeqNumber AS prev_Seq
,c.ItemId AS next_Itm
,c.SeqNumber AS next_Seq
FROM b
JOIN b c ON c.rn = b.rn + 1 -- next row
WHERE c.ItemId = b.ItemId -- only with same ItemId
AND c.SeqNumber <> (b.SeqNumber + 1)%256 -- Seq cycles modulo 256
)
SELECT Id, prev_Itm, 'Previous' AS PrevNext, prev_Seq
FROM x
UNION ALL
SELECT Id, next_Itm ,'Next', next_Seq
FROM x
ORDER BY Id, PrevNext DESC
完全生成所要求的结果。
请参阅complete working demo on data.SE。
此解决方案考虑了Id
列中的缺口,因为在问题中没有提及无间隙的Ids序列。
我在上面的查询中更新了CTE以符合您的最新版本 - 或者我认为。
使用定义行序列的列。根据需要为ORDER BY
子句添加尽可能多的列以打破关系。
对您的最新更新的解释对我来说并不完全清楚,但我认为您只需挤进DateTimeTrx
即可实现您的目标。我还在ORDER BY中SeqNumber
打破了相同DateTimeTrx
留下的关系。 我编辑了上面的查询。