2011-12-16 36 views
5

Tôi có bảng sau:đệ quy CTE - củng cố bắt đầu và ngày kết thúc

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 

Và đang cố gắng để đạt được các kết quả sau đó hàng liên tiếp với tình trạng tương tự được sáp nhập vào một hàng với một cách hiệu quả từ và đến phạm vi ngày:

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 

Tôi có thể nhận CTE đệ quy để xuất đúng ngày_to_datetime dựa trên hàng tiếp theo nhưng gặp sự cố khi hợp nhất phạm vi.

Mã để tạo ra dữ liệu mẫu:

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') 
+0

Ồ, và tôi không muốn sử dụng con trỏ hoặc vòng lặp vì kế hoạch là sử dụng logic này trong chế độ xem. – shakedown7

+0

Điều gì xảy ra nếu bạn không có mục nhập cho một ngày? Điều đó có nên được coi là một khoảng trống trong chuỗi không? ví dụ. giả sử dòng '('Hoạt động', '2011-01-02')' không có ở đó? –

Trả lời

8

EDIT SQL cập nhật theo nhận xét.

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 

Đây không phải là đệ quy, nhưng đó có thể là một điều tốt.


Nó không đối phó với những khoảng trống trong dữ liệu của bạn. Để giải quyết vấn đề đó, bạn có thể tạo bảng lịch, với mọi ngày có liên quan và tham gia vào đó để điền vào các ngày bị thiếu có trạng thái 'không xác định' và sau đó chạy truy vấn dựa vào đó. (Infact bạn cate làm điều đó một CTE được sử dụng bởi CTE ở trên).

Hiện nay ...
- Nếu dòng 2 đã mất tích, nó sẽ không thay đổi kết quả
- Nếu hàng 3 đã mất tích, các end_date của hàng đầu tiên sẽ thay đổi

hành vi khác nhau có thể được xác định bằng cách chuẩn bị dữ liệu của bạn hoặc các phương pháp khác. Chúng tôi cần biết logic kinh doanh bạn cần.


Nếu bất kỳ một ngày có thể có nhiều mục trạng thái, bạn cần xác định những gì logic bạn muốn nó làm theo. Hiện tại, hành vi là không xác định, nhưng bạn có thể sửa điều đó đơn giản bằng cách thêm customer_status vào các phần ORDER BY ROW_NUMBER().

+0

Hoàn hảo - cảm ơn! – shakedown7

+0

Một vấn đề tôi thấy (mà tôi nghĩ rằng làm cho giải pháp hoàn toàn khác) - the effective_to_datetime phải bằng với effect_from_datetime của hàng tiếp theo. – shakedown7

+0

@ shakedown7 - Đó là tình huống "khoảng cách" mà tôi đã đề cập đến. Nếu bạn có khoảng trống thì giải pháp đơn giản nhất là LEFT JOIN vào bảng lịch để điền vào các khoảng trống. Điều này sẽ khiến ba loại nhóm xuất hiện, một trong số đó liên quan đến khoảng trống của bạn và bạn có thể đặt tên hoặc chọn lọc ra sau đó. – MatBailie

Các vấn đề liên quan