删除/忽略具有非重叠数字序列的条目(不是日期序列)

时间:2018-04-09 12:14:49

标签: sql sql-server sequence

我有条目可以根据句号类型和从/到值形成序列。

期间类型可以是“W”(可能的周数范围1-53),“M”(月份1-12)和一些特殊类型但在一年内且始终具有范围1..x

条目可以覆盖(完整)范围,也可以有多个条目覆盖范围(有或没有间隙,不一定是整个范围)。序列也可以在允许的范围内的某个地方开始。

如此有效:

W    1   12
W   13   25
W   26   52

无效

W    1   12
W   11   53 <-- overlap

现在我需要一种过滤/忽略有效的方法,只显示无效的方法。不幸的是,它必须在SQL中,因为它适用于不支持任何脚本的报表工具。

在小提琴http://www.sqlfiddle.com/#!18/f2c32/1中,W 1-53的条目是无效的。

(带有“NULL”的结果行仅用于可视间距)

1 个答案:

答案 0 :(得分:0)

下面是一个使用LEAD窗口函数获取下一个范围并将当前范围与下一个范围进行比较的版本。

SQL Fiddle

MS SQL Server 2017架构设置

CREATE TABLE [dbo].[Test](
    [customer] [nchar](10) NULL,
    [key1] [nchar](10) NULL,
    [key2] [nchar](10) NULL,
    [key3] [nchar](10) NULL,
    [period] [nchar](1) NULL,
    [period_from] [int] NULL,
    [period_to] [int] NULL
) ON [PRIMARY]


INSERT INTO [dbo].[Test]([customer], [key1], [key2], [key3], [period], [period_from], [period_to])
VALUES 
(N'A         ', N'XYZ       ', N'123       ', N'000       ', N'W', 1, 53), 
(N'A         ', N'XYZ       ', N'123       ', N'111       ', N'W', 1, 53),
(N'A         ', N'ABC       ', N'123       ', N'000       ', N'Q', 1, 2), 
(N'A         ', N'ABC       ', N'123       ', N'333       ', N'Q', 3, 3), 
(N'A         ', N'YYY       ', N'321       ', N'CCC       ', N'W', 1, 20),
(N'A         ', N'YYY       ', N'321       ', N'DDD       ', N'W', 21, 30),
(N'A         ', N'YYY       ', N'321       ', N'EEE       ', N'W', 31, 53),

(N'B         ', N'XYZ       ', N'123       ', N'000       ', N'W', 1, 53), 
(N'B         ', N'XYZ       ', N'123       ', N'111       ', N'W', 1, 53),
(N'B         ', N'ABC       ', N'123       ', N'000       ', N'Q', 1, 2), 
(N'B         ', N'ABC       ', N'123       ', N'333       ', N'Q', 3, 3), 
(N'B         ', N'YYY       ', N'321       ', N'CCC       ', N'W', 1, 20),
(N'B         ', N'YYY       ', N'321       ', N'DDD       ', N'W', 21, 30),
(N'B         ', N'YYY       ', N'321       ', N'EEE       ', N'W', 31, 53)

查询1

    -- This solution assumes that the unique keys are (customer, key1, key2 and period)
    -- Adjust based on your needs
    ;WITH WithNext AS (select 
      *, 
      LEAD(period_from) OVER(PARTITION BY customer, key1, key2, period ORDER BY period_from, period_to) AS next_period_from,
      LEAD(period_to) OVER(PARTITION BY customer, key1, key2, period ORDER BY period_from, period_to) AS next_period_to
      from Test
    ) 
    SELECT * FROM Test t
     WHERE NOT EXISTS (
       SELECT * FROM WithNext w 
       WHERE 
         w.customer = t.customer 
         AND w.key1 = t.key1
         AND w.key2 = t.key2
         AND w.period = t.period
         AND (w.next_period_from BETWEEN w.period_from AND w.period_to)
      )
    ORDER BY customer, key1, key2, period

<强> Results

|   customer |       key1 |       key2 |       key3 | period | period_from | period_to |
|------------|------------|------------|------------|--------|-------------|-----------|
| A          | ABC        | 123        | 000        |      Q |           1 |         2 |
| A          | ABC        | 123        | 333        |      Q |           3 |         3 |
| A          | YYY        | 321        | CCC        |      W |           1 |        20 |
| A          | YYY        | 321        | DDD        |      W |          21 |        30 |
| A          | YYY        | 321        | EEE        |      W |          31 |        53 |
| B          | ABC        | 123        | 000        |      Q |           1 |         2 |
| B          | ABC        | 123        | 333        |      Q |           3 |         3 |
| B          | YYY        | 321        | CCC        |      W |           1 |        20 |
| B          | YYY        | 321        | DDD        |      W |          21 |        30 |
| B          | YYY        | 321        | EEE        |      W |          31 |        53 |