2017-02-27 19 views
1

のは、私はテーブルを以下しているとしましょう:SQL Serverの - 1ヶ月のレコードに複数ヶ月以上の分割記録

ID | user | from  | to   | loan 
1 | BB | 01/01/2016 | 01/05/2016 | 50 
2 | AD | 01/01/2016 | 01/03/2016 | 25 
3 | AD | 01/03/2016 | 17/05/2016 | 30 

この表のloanが毎月あります。したがって、ユーザーBBは、2006年1月1日から2011年5月1日まで50コイン/月を獲得しました。これを行うことができる方法で

ID | user | from  | to   | loan 
1 | BB | 01/01/2016 | 01/02/2016 | 50 
1 | BB | 01/02/2016 | 01/03/2016 | 50 
1 | BB | 01/03/2016 | 01/04/2016 | 50 
1 | BB | 01/04/2016 | 01/05/2016 | 50 
2 | AD | 01/01/2016 | 01/02/2016 | 25 
2 | AD | 01/02/2016 | 01/03/2016 | 25 
3 | AD | 01/03/2016 | 01/04/2016 | 30 
3 | AD | 01/04/2016 | 01/05/2016 | 30 
3 | AD | 01/05/2016 | 17/05/2016 | 30 

任意のアイデア/提案:私は、次のレコードにこれを分割したいですか?

+0

再帰CTEや、あなたのデータ –

+1

しないのはなぜで参加カレンダーのテーブルのどちらかIDが3のレコードは3つのレコードに分割されます(「01/03/2016 - 01/04/2016」、「01/04/2016 - 01/05/2016」、「01/05/2016 - 17/05/2016)? – GarethD

+0

@GarethD私の悪い、私はそこのレコードを見逃した。編集されました。 – DenStudent

答えて

3

あなたはこれを試すことができます。

SET DATEFORMAT dmy; 
DECLARE @Dummy TABLE(ID INT,[user] VARCHAR(100),[from] DATE,[to] DATE,loan INT); 
INSERT INTO @Dummy VALUES 
(1,'BB','01/01/2016','01/05/2016',50) 
,(2,'AD','01/01/2016','01/03/2016',25) 
,(3,'AD','01/03/2016','17/05/2016',30); 

DECLARE @FirstDay DATE='01/01/2016'; 

WITH SomeNumbers AS --replace this with a values/tally/numbers/date table 
(
    SELECT * FROM(VALUES(0),(1),(2),(3)) AS t(Nr) 
) 


SELECT DISTINCT 
     x.FirstOfMonth 
     ,FittingData.* 
FROM SomeNumbers 
CROSS APPLY(SELECT DATEADD(MONTH,SomeNumbers.Nr,@FirstDay) AS FirstOfMonth) AS x 
CROSS APPLY(SELECT * FROM @Dummy AS d WHERE x.FirstOfMonth>=d.[from] AND x.FirstOfMonth<d.[to]) AS FittingData 
WHERE ID IS NOT NULL 
ORDER BY ID,[from] 

結果

+--------------+----+------+------------+------------+------+ 
| FirstOfMonth | ID | user | from  | to   | loan | 
+--------------+----+------+------------+------------+------+ 
| 2016-01-01 | 1 | BB | 2016-01-01 | 2016-05-01 | 50 | 
+--------------+----+------+------------+------------+------+ 
| 2016-02-01 | 1 | BB | 2016-01-01 | 2016-05-01 | 50 | 
+--------------+----+------+------------+------------+------+ 
| 2016-03-01 | 1 | BB | 2016-01-01 | 2016-05-01 | 50 | 
+--------------+----+------+------------+------------+------+ 
| 2016-04-01 | 1 | BB | 2016-01-01 | 2016-05-01 | 50 | 
+--------------+----+------+------------+------------+------+ 
| 2016-01-01 | 2 | AD | 2016-01-01 | 2016-03-01 | 25 | 
+--------------+----+------+------------+------------+------+ 
| 2016-02-01 | 2 | AD | 2016-01-01 | 2016-03-01 | 25 | 
+--------------+----+------+------------+------------+------+ 
| 2016-03-01 | 3 | AD | 2016-03-01 | 2016-05-17 | 30 | 
+--------------+----+------+------------+------------+------+ 
| 2016-04-01 | 3 | AD | 2016-03-01 | 2016-05-17 | 30 | 
+--------------+----+------+------------+------------+------+ 
1
;WITH testtable(ID,[USER],[from],[to],loan)AS(
    SELECT 1,'BB',CONVERT(DATE,'01/01/2016'),CONVERT(DATE,'01/05/2016'),50 UNION all 
    SELECT 2,'AD','01/01/2016','01/03/2016',25 UNION all 
    SELECT 3 ,'AD','01/03/2016','01/05/2016',30 
) 
SELECT t.ID,t.[USER],DATEADD(d,sv.number,t.[FROM]) AS [From],dateadd(d,sv.number+1,t.[FROM]) AS [To],t.loan FROM testtable AS t 
INNER JOIN master.dbo.spt_values AS sv ON sv.type='P' AND sv.number BETWEEN 0 AND DATEDIFF(d,t.[FROM],t.[TO])-1 
 
ID   USER From  To   loan 
----------- ---- ---------- ---------- ----------- 
1   BB 2016-01-01 2016-01-02 50 
1   BB 2016-01-02 2016-01-03 50 
1   BB 2016-01-03 2016-01-04 50 
1   BB 2016-01-04 2016-01-05 50 
2   AD 2016-01-01 2016-01-02 25 
2   AD 2016-01-02 2016-01-03 25 
3   AD 2016-01-03 2016-01-04 30 
3   AD 2016-01-04 2016-01-05 30