缺少组内重复序列的间隙

时间:2011-12-02 18:30:11

标签: sql tsql

我们有一张包含以下数据的表

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中实现这一目标?

1 个答案:

答案 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序列。


编辑2:回答更新的问题:

我在上面的查询中更新了CTE以符合您的最新版本 - 或者我认为。

使用定义行序列的列。根据需要为ORDER BY子句添加尽可能多的列以打破关系。

对您的最新更新的解释对我来说并不完全清楚,但我认为您只需挤进DateTimeTrx即可实现您的目标。我还在ORDER BY中SeqNumber打破了相同DateTimeTrx留下的关系。 我编辑了上面的查询。