2016-01-22 77 views
0

我有一個協議表和一個計劃表。計劃是一個協議的孩子,並有一個FK的參考。SQL或SSIS找到丟失的日期範圍?

同一協議的所有計劃都應該填滿協議的整個範圍。但是,協議中還有一些缺失的計劃。

無論如何在SQL或SSIS中獲取「失蹤」計劃的列表?

協議表

 
+--------------+----------------------+--------------------+ 
| Agreement Id | Agreement Start Date | Agreement End Date | 
+--------------+----------------------+--------------------+ 
|   1 | 1/1/2010    | 12/31/2016   | 
+--------------+----------------------+--------------------+ 

計劃表

 
+--------------+---------+-----------------+---------------+ 
| Agreement Id | Plan Id | Plan Start Date | Plan End Date | 
+--------------+---------+-----------------+---------------+ 
|   1 |  1 | 1/1/2010  | 12/31/2010 | 
|   1 |  2 | 1/1/2012  | 12/31/2012 | 
|   1 |  3 | 1/1/2014  | 12/31/2016 | 
+--------------+---------+-----------------+---------------+

期望中的計劃表

 
+--------------+---------+-----------------+---------------+ 
| Agreement Id | Plan Id | Plan Start Date | Plan End Date | 
+--------------+---------+-----------------+---------------+ 
|   1 |  1 | 1/1/2010  | 12/31/2010 | 
|   1 |  4 | 1/1/2011  | 12/31/2011 | 
|   1 |  2 | 1/1/2012  | 12/31/2012 | 
|   1 |  5 | 1/1/2013  | 12/31/2013 | 
|   1 |  3 | 1/1/2014  | 12/31/2016 | 
+--------------+---------+-----------------+---------------+ 

所以基本上,我想要得到的協議1這將是這些失蹤的計劃行:

 
+--------------+---------+-----------------+---------------+ 
| Agreement Id | Plan Id | Plan Start Date | Plan End Date | 
+--------------+---------+-----------------+---------------+ 
|   1 |  4 | 1/1/2011  | 12/31/2011 | 
|   1 |  5 | 1/1/2013  | 12/31/2013 | 
+--------------+---------+-----------------+---------------+ 
+0

mysql和ssis? –

+0

任何涉及SQL或SSIS的解決方案都會非常棒! – Juc

+0

Mysql是不同的產品 – Shadow

回答

1

這是爲MS SQL Server編寫的,因此如果您正在編寫MySQL,您可能需要調整日期函數,但我相信這應該可行。我不認爲我在覆蓋協議開始缺少計劃的情況,所以我會給一些思想和添加代碼爲不久:

SELECT 
    DATEADD(DAY, 1, P.end_date) AS start_date, 
    COALESCE(DATEADD(DAY, -1, P3.start_date), A.end_date) AS end_date 
FROM 
    dbo.Agreements A 
INNER JOIN dbo.Plans P ON 
    P.agreement_id = A.agreement_id 
LEFT OUTER JOIN dbo.Plans P2 ON P2.agreement_id = A.agreement_id AND P2.start_date = DATEADD(DAY, 1, P.end_date) 
LEFT OUTER JOIN dbo.Plans P3 ON P3.agreement_id = A.agreement_id AND P3.start_date > P.end_date 
LEFT OUTER JOIN dbo.Plans P4 ON P4.agreement_id = A.agreement_id AND P4.start_date BETWEEN P.end_date AND P3.start_date AND P4.plan_id <> P3.plan_id 
WHERE 
    P.end_date <> A.end_date AND 
    P2.agreement_id IS NULL AND 
    P4.agreement_id IS NULL 

這種方法也應該抓住缺少啓動和結束計劃,但使用窗口函數ROW_NUMBER排隊填滿。你可以在沒有ROW_NUMBER的情況下完成它,但它要複雜得多。我也不確定在SQL中沒有這麼簡單的方法,但這是我開始打字時首先想到的:

;WITH CTE_MissingEndDates AS 
(
    SELECT agreement_id, missing_end_date, ROW_NUMBER() OVER (PARTITION BY agreement_id ORDER BY missing_end_date) AS row_num 
    FROM 
    (
     SELECT 
      A.agreement_id, 
      DATEADD(DAY, -1, P1.start_date) AS missing_end_date 
     FROM 
      dbo.Agreements A 
     INNER JOIN dbo.Plans P1 ON P1.agreement_id = A.agreement_id 
     LEFT OUTER JOIN dbo.Plans P2 ON P2.agreement_id = A.agreement_id AND P2.end_date = DATEADD(DAY, -1, P1.start_date) 
     WHERE 
      P1.start_date > A.start_date 
     UNION 
     SELECT A2.agreement_id, A2.end_date FROM dbo.Agreements A2 WHERE NOT EXISTS (SELECT * FROM dbo.Plans WHERE agreement_id = A2.agreement_id AND end_date = A2.end_date) 
    ) SQ 
), 
CTE_MissingStartDates AS 
(
    SELECT agreement_id, missing_start_date, ROW_NUMBER() OVER (PARTITION BY agreement_id ORDER BY missing_start_date) AS row_num 
    FROM 
    (
     SELECT 
      A.agreement_id, 
      DATEADD(DAY, 1, P1.end_date) AS missing_start_date 
     FROM 
      dbo.Agreements A 
     INNER JOIN dbo.Plans P1 ON P1.agreement_id = A.agreement_id 
     LEFT OUTER JOIN dbo.Plans P2 ON P2.agreement_id = A.agreement_id AND P2.start_date = DATEADD(DAY, 1, P1.end_date) 
     WHERE 
      P1.end_date < A.end_date 
     UNION 
     SELECT A2.agreement_id, A2.start_date FROM dbo.Agreements A2 WHERE NOT EXISTS (SELECT * FROM dbo.Plans WHERE agreement_id = A2.agreement_id AND start_date = A2.start_date) 
    ) SQ 
) 
SELECT 
    MSD.missing_start_date, 
    MED.missing_end_date 
FROM 
    CTE_MissingStartDates MSD 
INNER JOIN CTE_MissingEndDates MED ON 
    MED.agreement_id = MSD.agreement_id AND 
    MED.row_num = MSD.row_num