2011-10-03 22 views
5

を持つレコードでカバーされていない時間のギャップが、私は料金レコード(f_fee_item)のテーブルを持っている検索:次のように開始日と終了日

Fee_Item_ID int 
Fee_Basis_ID int 
Start_Date  date 
End_Date  date 

(無関係な列は削除)

は、レコードのことを想定します同じFee_Basis_IDは重複しません。

Fee_Basis_IDの手数料レコードの各ギャップのStart_DateとEnd_Dateを、@Query_Start_Date@Query_End_Dateの間で見つける必要があります。手数料が課金されていないすべての期間の手数料を計算するには、このデータが必要です。

また、Fee_Basis_ID(Fee_Basis_IDは、D_Fee_Basis.Fee_Basis_IDへの外部キーです)があれば、料金レコードが全くない場合はレコードを返すクエリが必要です。

例えば:

@Query_Start_Date = '2011-01-01' 
@Query_Start_Date = '2011-09-30' 

D_Fee_Basis:

F_Fee_Item 
1 
2 
3 

F_Fee_Item:

Fee_Item_ID Fee_Basis_ID Start_Date End_Date 
1   1    2011-01-01 2011-03-31 
2   1    2011-04-01 2011-06-30 
3   2    2011-01-01 2011-03-31 
4   2    2011-05-01 2011-06-30 

必要な結果:

Fee_Basis_ID Start_Date End_Date 
1    2011-07-01 2011-09-30 
2    2011-04-01 2011-04-30 
2    2011-07-01 2011-09-30 
3    2011-01-01 2011-09-30 

私はそれを稼働させようと努力しているが、運がないためにさまざまな自己結合を試みてきた。

助けてください!ここで

+0

'F_Fee_Itemを持っているどのように多くのレコード'テーブル? –

+0

システムの寿命の間、5桁未満のままになることが予想されます。 – Aphillippe

答えて

2

は、ソリューションです:結果のための

declare @Query_Start_Date date= '2011-01-01' 
declare @Query_End_Date date = '2011-09-30' 

declare @D_Fee_Basis table(F_Fee_Item int) 
insert @D_Fee_Basis values(1) 
insert @D_Fee_Basis values(2) 
insert @D_Fee_Basis values(3) 

declare @F_Fee_Item table(Fee_Item_ID int, Fee_Basis_ID int,Start_Date date,End_Date date) 
insert @F_Fee_Item values(1,1,'2011-01-01','2011-03-31') 
insert @F_Fee_Item values(2,1,'2011-04-01','2011-06-30') 
insert @F_Fee_Item values(3,2,'2011-01-01','2011-03-31') 
insert @F_Fee_Item values(4,2,'2011-05-01','2011-06-30') 

;with a as 
(-- find all days between Start_Date and End_Date 
select @Query_Start_Date d 
union all 
select dateadd(day, 1, d) 
from a 
where d < @Query_end_Date 
), b as 
(--find all unused days 
select a.d, F_Fee_Item Fee 
from a, @D_Fee_Basis Fee 
where not exists(select 1 from @F_Fee_Item where a.d between Start_Date and End_Date and Fee.F_Fee_Item = Fee_Basis_ID) 
), 
c as 
(--find all start dates 
select d, Fee, rn = row_number() over (order by fee, d) from b 
where not exists (select 1 from b b2 where dateadd(day,1, b2.d) = b.d and b2.Fee= b.Fee) 
), 
e as 
(--find all end dates 
select d, Fee, rn = row_number() over (order by fee, d) from b 
where not exists (select 1 from b b2 where dateadd(day,-1, b2.d) = b.d and b2.Fee= b.Fee) 
) 
--join start dates with end dates 
select c.Fee Fee_Basis_ID, c.d Start_Date, e.d End_Date from c join e on c.Fee = e.Fee and c.rn = e.rn 
option (maxrecursion 0) 

リンク: http://data.stackexchange.com/stackoverflow/q/114193/

+0

パーフェクト。助けてくれてありがとう。私は本当にCTEを正しく理解する必要があります。 – Aphillippe

1

YACTES:

CREATE TABLE dbo.TestData 
(
    Fee_Item_ID  INT PRIMARY KEY, 
    Fee_Basis_ID INT NOT NULL, 
    [Start_Date] DATE NOT NULL, 
    [End_Date]  DATE NOT NULL 
); 
CREATE UNIQUE INDEX [email protected] 
ON  dbo.TestData(Fee_Basis_ID, [Start_Date]) 
INCLUDE (End_Date); 

INSERT dbo.TestData 
VALUES 
(1,1,'2011-02-01','2011-03-31'), 
(2,1,'2011-04-01','2011-05-31'), 
(3,2,'2011-01-01','2011-03-31'), 
(4,2,'2011-05-01','2011-06-30'), 
(5,2,'2011-11-01','2011-11-30'), 
(6,3,'2011-05-01','2011-06-30'); 

CREATE TABLE dbo.TestData2(Fee_Basis_ID INT PRIMARY KEY); 
INSERT dbo.TestData2 VALUES (1),(2),(3); 

DECLARE @Query_Start_Date DATE = '2011-01-01' 
    ,@Query_End_Date DATE = '2011-09-30'; 

;WITH FeeRank 
AS 
(
    SELECT a.Fee_Basis_ID 
      ,a.[Start_Date] 
      ,a.End_Date 
      ,ROW_NUMBER() OVER(PARTITION BY a.Fee_Basis_ID ORDER BY a.[Start_Date]) GroupRowNum 
      ,COUNT(*)  OVER(PARTITION BY a.Fee_Basis_ID) GroupCount 
    FROM dbo.TestData a 
    WHERE @Query_Start_Date <= a.[Start_Date] 
    AND  a.[End_Date] <= @Query_End_Date 
), Scan 
AS 
(
    SELECT a.Fee_Basis_ID, @Query_Start_Date [Start_Date], DATEADD(DAY,-1,a.[Start_Date]) End_Date 
    FROM FeeRank a 
    WHERE a.GroupRowNum = 1 
    AND  @Query_Start_Date <> a.[Start_Date] 

    UNION ALL 

    SELECT a.Fee_Basis_ID, DATEADD(DAY,1,a.End_Date) b, @Query_End_Date c 
    FROM FeeRank a 
    WHERE a.End_Date <> @Query_End_Date AND a.GroupRowNum = a.GroupCount 

    UNION ALL 

    SELECT crt.Fee_Basis_ID, DATEADD(DAY,1,prev.End_Date), DATEADD(DAY,-1,crt.[Start_Date]) 
    FROM FeeRank prev 
    INNER JOIN FeeRank crt ON prev.Fee_Basis_ID = crt.Fee_Basis_ID 
    AND  prev.GroupRowNum + 1 = crt.GroupRowNum 
    WHERE DATEDIFF(DAY,prev.[End_Date],crt.[Start_Date]) <> 1 
) 
SELECT cte.Fee_Basis_ID, cte.[Start_Date], cte.End_Date 
FROM Scan cte 
UNION ALL 
SELECT b.Fee_Basis_ID, NULL, NULL 
FROM dbo.TestData2 b 
WHERE b.Fee_Basis_ID NOT IN (SELECT c.Fee_Basis_ID FROM dbo.TestData c) 
ORDER BY Fee_Basis_ID; 

DROP TABLE dbo.TestData; 
DROP TABLE dbo.TestData2 

YACTES:もう一つのCTEソリューション

関連する問題