我有这张桌子:
Year Holiday HolidayStart HolidayEnd
2008 Holiday1 09/09/2008 30/09/2008
2008 Holiday2 01/10/2008 21/10/2008
2008 Holiday3 22/10/2008 12/11/2008
2008 Holiday4 01/12/2008 21/12/2008
2008 Holiday5 02/01/2008 22/01/2008
2008 Holiday6 01/03/2008 21/03/2008
2008 Holiday7 23/03/2008 20/04/2008
2008 Holiday8 27/04/2008 16/05/2008
我想转换它,以便我每个日期都有一行,比如
Year Holiday Dates of the holiday
2008 Holiday1 09/09/2008
2008 Holiday1 10/09/2008
2008 Holiday1 11/09/2008
2008 Holiday1 12/09/2008
2008 Holiday2 01/10/2008
2008 Holiday2 02/10/2008
2008 Holiday2 03/10/2008
2008 Holiday2 04/10/2008
我该怎么做?
答案 0 :(得分:1)
您似乎有额外的过滤要求(因为Holiday1
和Holiday2
中显然有22天),但您可以通过预测涵盖整个范围的连续日期范围来实现此目的将Holidays
表插入到其中:
WITH CTENumbers AS
(
SELECT 0 AS Number
UNION ALL
SELECT Number + 1
FROM CTENumbers
WHERE Number < 300
),
DateRanges AS
(
SELECT
MIN(HolidayStart) AS MinStart,
MAX(HolidayStart) AS MaxStart
FROM Holidays
)
SELECT YEAR, Holiday, DATEADD(dd, cte.Number, dr.MinStart) AS DateOfTheHoliday
FROM
CTENumbers cte,
DateRanges dr,
Holidays h
WHERE
DATEADD(dd, cte.Number, dr.MinStart)
BETWEEN h.HolidayStart AND h.HolidayEnd
AND Holiday IN ('Holiday1', 'Holiday2')
ORDER BY HolidayStart
OPTION( MAXRECURSION 1000)
如果您需要定期执行此操作,我建议您在永久表中保留日期范围(由CTE预测为偏离开始日期的偏移量)。
答案 1 :(得分:0)
这有效,虽然它有点倒退使用这样的SQL。第一个代码块创建了一些临时表来演示解决方案。第二个块是实际的解决方案。
CREATE TABLE #demo (
[year] int ,
holiday nvarchar( 50 ) ,
holidaystart date ,
holidayend date );
INSERT INTO #demo ( [year] ,
holiday ,
holidaystart ,
holidayend )
VALUES
( 2008 ,
'Holiday1' ,
'2008-09-09' ,
'2008-09-30' ) ,
( 2008 ,
'Holiday2' ,
'2008-10-01' ,
'2008-10-21' ) ,
( 2008 ,
'Holiday3' ,
'2008-10-22' ,
'2008-11-12' );
CREATE TABLE #result (
[year] int ,
holiday nvarchar( 50 ) ,
holidaydate date );
这是为您提供数据的实际代码,首先使用顶部来创建演示数据。
SELECT ROW_NUMBER( ) OVER( ORDER BY holidaystart ) rownum ,
holiday ,
holidaystart ,
holidayend ,
[year]
INTO #foreach_item
FROM #demo;
DECLARE
@Iter int = ( SELECT MIN( rownum )
FROM #foreach_item );
DECLARE
@Max int = ( SELECT MAX( rownum )
FROM #foreach_item );
WHILE @Iter <= @Max
BEGIN
DECLARE
@First_Day date = DATEADD( dd , -1 , ( SELECT holidaystart
FROM #foreach_item
WHERE rownum = @Iter ));
DECLARE
@Last_Day date = ( SELECT holidayend
FROM #foreach_item
WHERE rownum = @Iter );
DECLARE
@Holiday nvarchar( 50 ) = ( SELECT holiday
FROM #foreach_item
WHERE rownum = @Iter );
WHILE @First_Day < @Last_Day
BEGIN
INSERT INTO #result
SELECT [year] ,
holiday ,
DATEADD( dd , 1 , @First_Day )
FROM #foreach_item
WHERE holiday = @Holiday;
SET @First_Day = DATEADD( dd , 1 , @First_Day );
END;
SET @Iter = @Iter + 1;
END;
SELECT *
FROM #result
ORDER BY holiday;