2013-03-26 147 views
1

我已經看到很多解決方案來識別日期範圍重疊的記錄,還有其他合併重疊範圍的示例。重疊日期範圍 - 僅識別重疊

但是我對顯示只有重疊發生的範圍的結果感興趣。事實上,我有3個ProductID(並且只有3個將存在),並且我試圖找出每個客戶的全部三個日期範圍。

SET NOCOUNT ON; 

CREATE TABLE #tmp 
(
    CustomerID integer 
    ,ProductID varchar(12) 
    ,Eff_Dt DATE 
    ,End_Dt DATE 
); 

-- Customer 1000: Expecting results to show 2 rows: 1/1 - 1/5 and 1/10 - 1/15 
INSERT INTO #tmp VALUES (1000,'PRODUCT_A','01-01-2013' ,'01-31-2013'); 
INSERT INTO #tmp VALUES (1000,'PRODUCT_B','01-01-2013' ,'01-05-2013'); 
INSERT INTO #tmp VALUES (1000,'PRODUCT_B','01-10-2013' ,'01-15-2013'); 
INSERT INTO #tmp VALUES (1000,'PRODUCT_C','01-01-2013' ,'01-31-2013'); 

-- Customer 2000: Expecting results to show 1 row: 1/19 - 1/31 
INSERT INTO #tmp VALUES (2000,'PRODUCT_A','01-01-2013' ,'01-31-2013'); 
INSERT INTO #tmp VALUES (2000,'PRODUCT_B','01-01-2013' ,'01-31-2013'); 
INSERT INTO #tmp VALUES (2000,'PRODUCT_C','01-19-2013' ,'01-31-2013'); 

-- Customer 3000: Expecting results to show no rows (or nulls) 
INSERT INTO #tmp VALUES (3000,'PRODUCT_A','01-01-2013' ,'01-10-2013'); 
INSERT INTO #tmp VALUES (3000,'PRODUCT_A','01-16-2013' ,'01-31-2013'); 
INSERT INTO #tmp VALUES (3000,'PRODUCT_B','01-01-2013' ,'01-12-2013'); 
INSERT INTO #tmp VALUES (3000,'PRODUCT_C','01-15-2013' ,'01-31-2013'); 

-- Customer 4000: Expecting results to show 1 row: 1/15 - 1/23 
INSERT INTO #tmp VALUES (4000,'PRODUCT_A','01-15-2013' ,'01-31-2013'); 
INSERT INTO #tmp VALUES (4000,'PRODUCT_B','01-01-2013' ,'01-31-2013'); 
INSERT INTO #tmp VALUES (4000,'PRODUCT_C','01-01-2013' ,'01-23-2013'); 

-- Customer 5000: Expecting results to show 0 rows 
INSERT INTO #tmp VALUES (5000,'PRODUCT_A','01-17-2013' ,'01-31-2013'); 
INSERT INTO #tmp VALUES (5000,'PRODUCT_B','01-01-2013' ,'01-10-2013'); 
INSERT INTO #tmp VALUES (5000,'PRODUCT_C','01-07-2013' ,'01-19-2013'); 

-- Customer 6000: Expecting results to show 3 rows: 1/11 - 1/12 1/17 - 1/22 1/26 - 1/27 
INSERT INTO #tmp VALUES (6000,'PRODUCT_A','01-01-2013' ,'01-04-2013'); 
INSERT INTO #tmp VALUES (6000,'PRODUCT_A','01-09-2013' ,'01-12-2013'); 
INSERT INTO #tmp VALUES (6000,'PRODUCT_A','01-17-2013' ,'01-22-2013'); 
INSERT INTO #tmp VALUES (6000,'PRODUCT_A','01-26-2013' ,'01-31-2013'); 
INSERT INTO #tmp VALUES (6000,'PRODUCT_B','01-04-2013' ,'01-28-2013'); 
INSERT INTO #tmp VALUES (6000,'PRODUCT_C','01-11-2013' ,'01-27-2013'); 

SET NOCOUNT OFF; 
/* ====== EXPECTED RESULTS ======================= 

CustomerID EFF_DT  END_DT 
1000   1/1/2013  1/5/2013 
1000   1/10/2013  1/15/2013 
2000   1/19/2013  1/31/2013 
4000   1/15/2013  1/23/2013 
6000   1/11/2013  1/12/2013 
6000   1/17/2013  1/22/2013 
6000   1/26/2013  1/27/2013 

===================================================*/ 
+0

這是SQLServer的? – 2013-03-26 15:15:24

+1

客戶5000不會從此數據集返回任何值,因爲它沒有日期範圍,其中所有3個產品重疊 - PRODUCT_A從不與PRODUCT_B重疊。 – 2013-03-26 15:29:30

回答

3

這裏的答案:

select t.customerid, t.eff_dt, count(distinct t2.productId), 
     MIN(t2.end_dt) as end_dt 
from #tmp t join 
    #tmp t2 
    on t.CustomerID = t2.CustomerID and 
     t.Eff_Dt between t2.Eff_Dt and t2.End_Dt 
group by t.CustomerID, t.eff_dt 
having count(distinct t2.productId) = 3 

這是使用自聯接來計算不同產品的每個eff_dt數量。你需要三種不同的產品,這就是having條款正在做的事情。

有三種不同的產品,直到其中一個結束。這將是生效日期後的第一個end_dt - 由min(end_dt)計算。

+0

這是一個很好的解決方案。我之前的嘗試嘗試了類似的方法,但是在每個可能的日期計算不同產品的數量 - 但是您的解決方案只計算每個EFF_DT上的不同產品 - 輝煌! – Josh 2013-03-26 15:47:25

1

嘗試:

select ab.CustomerID, 
     case when ab_Eff_Dt > c.Eff_Dt then ab_Eff_Dt else c.Eff_Dt end abc_Eff_Dt, 
     case when ab_End_Dt < c.End_Dt then ab_End_Dt else c.End_Dt end abc_End_Dt 
from 
(select a.CustomerID, 
     case when a.Eff_Dt > b.Eff_Dt then a.Eff_Dt else b.Eff_Dt end ab_Eff_Dt, 
     case when a.End_Dt < b.End_Dt then a.End_Dt else b.End_Dt end ab_End_Dt 
from #tmp a 
join #tmp b 
    on a.CustomerID = b.CustomerID and a.Eff_Dt < b.End_Dt and b.Eff_Dt < a.End_Dt 
where a.ProductID = 'PRODUCT_A' and b.ProductID = 'PRODUCT_B') ab 
join #tmp c 
    on ab.CustomerID = c.CustomerID and ab_Eff_Dt < c.End_Dt and c.Eff_Dt < ab_End_Dt 
where c.ProductID = 'PRODUCT_C' 

(SQLFiddle here