開始日のサブセットの時系列日付(たとえば10)のベクトルを作成する必要があります。
次のステートメントは、'2010-01-01'
から始まる10個の連続する日付を返します。
;with cte as
(select 1 i union all
select i+1 i from cte where i < 10)
select '2010-01-01' as start_date, dateadd(d, i-1, '2010-01-01') AS trial_date
INTO #tmp_trialdates
FROM cte
複数の開始日(必ずしも連続的ではない)のテーブル(または他のデータセット)のクエリを組み込み、各開始日の時系列日付を生成し、1つの出力テーブルにデータを入力する方法について、誰かが何か提案はありますか?
このためには、再帰CTEのアンカーセットを変更する必要があるため、各行は、再帰部分を開始する前に、他のテーブルの日付で始まります。
DECLARE @AmountDays INT = 10
;WITH GeneratedDays AS
(
-- Anchor
SELECT
DateSeriesIdentifier = T.DateSeriesIdentifier,
Date = T.Date, -- Assuming it's DATE data type
RecursionLevel = 1
FROM
OtherTable AS T
UNION ALL
-- Recursion
SELECT
DateSeriesIdentifier = G.DateSeriesIdentifier,
Date = DATEADD(DAY, 1, G.Date),
RecursionLevel = G.RecursionLevel + 1
FROM
GeneratedDays AS G
WHERE
G.RecursionLevel + 1 <= @AmountDays
)
SELECT
G.DateSeriesIdentifier,
G.Date,
G.RecursionLevel
FROM
GeneratedDays AS G
ORDER BY
G.DateSeriesIdentifier,
G.RecursionLevel
これは、日付をテストするために使用したセットの結果です2016-02-04
、2018-01-19
および2018-08-30
:
DateSeriesIdentifier Date RecursionLevel
21 2016-02-04 1
21 2016-02-05 2
21 2016-02-06 3
21 2016-02-07 4
21 2016-02-08 5
21 2016-02-09 6
21 2016-02-10 7
21 2016-02-11 8
21 2016-02-12 9
21 2016-02-13 10
620646 2018-01-19 1
620646 2018-01-20 2
620646 2018-01-21 3
620646 2018-01-22 4
620646 2018-01-23 5
620646 2018-01-24 6
620646 2018-01-25 7
620646 2018-01-26 8
620646 2018-01-27 9
620646 2018-01-28 10
639701 2018-08-30 1
639701 2018-08-31 2
639701 2018-09-01 3
639701 2018-09-02 4
639701 2018-09-03 5
639701 2018-09-04 6
639701 2018-09-05 7
639701 2018-09-06 8
639701 2018-09-07 9
639701 2018-09-08 10
ここに1つの試みがあります。開始日と必要な期間の日数をinitに適切に追加します。
with init(start_date,num_days) as ( select cast('2010-01-01' as date), 1
union all
select cast('2017-11-12' as date), 4)
, iter(start_date, num_days, dt) as (
select start_date, num_days, start_date as dt from init
union all
select start_date, num_days, dateadd(DAY, 1, dt)
from iter where dt < dateadd(DAY, num_days-1, start_date)
)
select start_date,num_days from iter
order by start_date, dt;
再帰的なCTEを使用して最終的な日付範囲を生成する代わりに、別のアプローチを使用します。 CTEは特定の再帰制限に制限されています。つまり、この制限よりも長い日付範囲は生成されません(デフォルトでは100に設定されていると思います)。この場合、100日を超えるデータ範囲を作成できないことを意味します。
私の提案は、CTEを使用していわゆるTally Tableを生成し、それをCROSS APPLYで使用して目的の結果を取得することです。これにより、「無制限」のデータ範囲をいくつでも作成できます。
整数の範囲を生成するテーブル値関数を作成してみましょう。
CREATE FUNCTION dbo.fnt_Numbers(@startValue int, @amount int)
RETURNS TABLE AS
RETURN
WITH lv0 AS (SELECT 0 g UNION ALL SELECT 0)
,lv1 AS (SELECT 0 g FROM lv0 a CROSS JOIN lv0 b) -- 4
,lv2 AS (SELECT 0 g FROM lv1 a CROSS JOIN lv1 b) -- 16
,lv3 AS (SELECT 0 g FROM lv2 a CROSS JOIN lv2 b) -- 256
,lv4 AS (SELECT 0 g FROM lv3 a CROSS JOIN lv3 b) -- 65,536
,Numbers AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS num FROM lv4)
SELECT @startValue + num - 1 AS n
FROM Numbers
WHERE num <= @amount;
次のように使用できます。
SELECT n FROM dbo.fnt_Numbers(0, 10);
結果の例:
次に、このコードを使用して、必要な時間範囲を生成できます。
CREATE TABLE #Date (
StartDate date NOT NULL,
DaysAmount int NOT NULL
);
--Example data
INSERT INTO #Date (StartDate,DaysAmount)
VALUES ('2018-08-31', 10), ('2000-10-10', 5);
--Review table content
SELECT StartDate, DaysAmount
FROM #Date;
--Generate ranges
SELECT Dates.*
FROM #Date
CROSS APPLY (SELECT DATEADD(day,n, StartDate) AS [Date] , n FROM fnt_Numbers(0, DaysAmount)) AS Dates
ORDER BY StartDate, n;
結果: