2014-05-12 1 views
1

J'ai ce tableau:besoin d'extraire un ensemble de lignes de date à partir d'une plage de 2 colonnes de date dans 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 

Je veux le convertir afin que je vais avoir une ligne pour chaque jour, comme ce

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 

Comment faire?

Répondre

0

Cela fonctionne, mais c'est un peu en arrière pour utiliser SQL comme ça. Ce premier bloc de code crée des tables temporaires pour illustrer la solution. Le deuxième bloc est la solution réelle.

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); 

Ceci est le code réel pour vous donner les données, utilisez d'abord la partie supérieure pour créer les données de démonstration.

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

Vous semblez avoir des exigences de filtrage supplémentaires (car il y a clairement 22 jours dans les deux Holiday1 et Holiday2), mais vous pouvez aborder ce en projetant une gamme continue de dates couvrant toute la gamme puis interpoler la table Holidays à elle:

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

Si vous devez le faire sur une base régulière, je vous recommande que persistez l'intervalle de dates (en projet édité par le CTE comme décalage par rapport à la date de début) dans une table permanente.

Questions connexes