递归CTE - 合并开始和结束日期

sha*_*wn7 6 sql t-sql sql-server

我有下表:

row_num customer_status    effective_from_datetime
------- ------------------ -----------------------
1       Active             2011-01-01
2       Active             2011-01-02
3       Active             2011-01-03
4       Suspended          2011-01-04
5       Suspended          2011-01-05
6       Active             2011-01-06
Run Code Online (Sandbox Code Playgroud)

我正在尝试获得以下结果,即具有相同状态的连续行合并为一行,并具有有效的起始和日期范围:

customer_status effective_from_datetime effective_to_datetime
--------------- ----------------------- ---------------------
Active          2011-01-01              2011-01-04
Suspended       2011-01-04              2011-01-06
Active          2011-01-06              NULL
Run Code Online (Sandbox Code Playgroud)

我可以得到一个递归CTE,根据下一行输出正确的effective_to_datetime,但是在合并范围时遇到问题.

用于生成样本数据的代码:

CREATE TABLE #temp
(
row_num INT IDENTITY(1,1),
customer_status VARCHAR(10),
effective_from_datetime DATE
)

INSERT INTO #temp
VALUES 
('Active','2011-01-01')
,('Active','2011-01-02')
,('Active','2011-01-03')
,('Suspended','2011-01-04')
,('Suspended','2011-01-05')
,('Active','2011-01-06')
Run Code Online (Sandbox Code Playgroud)

Mat*_*lie 9

编辑 SQL根据评论更新.

WITH
  group_assigned_data AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY customer_status ORDER BY effective_from_date) AS status_sequence_id,
    ROW_NUMBER() OVER (                             ORDER BY effective_from_date) AS sequence_id,
    customer_status,
    effective_from_date
  FROM
    your_table
)
,
  grouped_data AS
(
  SELECT
    customer_status,
    MIN(effective_from_date)   AS min_effective_from_date,
    MAX(effective_from_date)   AS max_effective_from_date
  FROM
    group_assigned_data
  GROUP BY
    customer_status,
    sequence_id - status_sequence_id
)
SELECT
  [current].customer_status,
  [current].min_effective_from_date       AS effective_from,
  [next].min_effective_from_date          AS effective_to
FROM
  grouped_data   AS [current]
LEFT JOIN
  grouped_data   AS [next]
    ON [current].max_effective_from_date = [next].min_effective_from_date + 1
ORDER BY
  [current].min_effective_from_date
Run Code Online (Sandbox Code Playgroud)

这不是递归的,但这可能是一件好事.


它不处理数据中的差距.为了解决这个问题,您可以创建一个包含每个相关日期的日历表,然后加入该日历表以填充"未知"状态的缺失日期,然后针对该日期运行查询.(事实上​​,你可以把它作为上面CTE使用的CTE).

目前...
- 如果第2行丢失,它不会改变结果
- 如果第3行丢失,第一行的end_date将改变

可以通过准备数据或其他方法来确定不同的行为.我们需要知道您需要的业务逻辑.


如果任何一个日期可以有多个状态条目,则需要定义要遵循的逻辑.目前行为是未定义的,但您可以像添加customer_statusORDER BYROW_NUMBER()的部分一样纠正它.