2014-05-12 67 views
1

从范围2个日期列中提取一组最新的行我有这个表:需要在TSQL

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

这个工作,虽然它有点倒退,像这样使用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; 
1

你似乎有额外的过滤器的需求(因为有明确22天两个Holiday1Holiday2),但你可以通过投影日期覆盖整个范围的连续范围,然后插在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)  

SqlFiddle here

如果你需要做这个定期,我建议你坚持下去的日期范围(如项目由CTE将其作为与开始日期的偏差)编入永久性表格中。