Générer des Dates entre les plages de dates

J'ai besoin de remplir une table qui stockera les plages de dates entre 2 dates données: 09/01/11-10/10/11

Donc, dans ce cas, la table commencerait à partir du 01/09/11 et stockerait chaque jour jusqu'au 10/10/11 Je me demandais s'il y avait une façon élégante de le faire dans SQL Server - j'utilise actuellement SQL Server 2008. Merci

27
demandé sur sll 2011-10-19 20:39:41

8 réponses

Facile sur SQL 2005+; plus facile si vous avez un nombre ou une table de pointage. Je l'ai simulé ci-dessous:

DECLARE @StartDate DATE = '20110901'
  , @EndDate DATE = '20111001'

SELECT  DATEADD(DAY, nbr - 1, @StartDate)
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS Nbr
          FROM      sys.columns c
        ) nbrs
WHERE   nbr - 1 <= DATEDIFF(DAY, @StartDate, @EndDate)

Si vous avez une table de pointage, remplacez la sous-requête par la table. Pas de récursivité.

23
répondu Stuart Ainsworth 2011-10-19 16:55:12

Essayez ceci si vous utilisez SQL Server 2005 ou plus récent:

WITH Dates AS (
        SELECT
         [Date] = CONVERT(DATETIME,'09/01/2011')
        UNION ALL SELECT
         [Date] = DATEADD(DAY, 1, [Date])
        FROM
         Dates
        WHERE
         Date < '10/10/2011'
) SELECT
 [Date]
FROM
 Dates
 OPTION (MAXRECURSION 45)

Un bon exemple de trucs cool que vous pouvez faire avec un CTE.

29
répondu Abe Miessler 2011-10-19 16:43:59

-- les Déclarations

DECLARE @dates TABLE(dt datetime)    
DECLARE @dateFrom datetime
DECLARE @dateTo datetime

SET @dateFrom = '2001/01/01'
SET @dateTo = '2001/01/12'

-- Requête:

WHILE(@dateFrom < @dateTo)
BEGIN
   SELECT @dateFrom = DATEADD(day, 1,@dateFrom)
   INSERT INTO @dates 
   SELECT @dateFrom
END

-- Sortie

SELECT * FROM @dates
9
répondu sll 2011-10-19 16:45:54

Utilisez la fonction F_TABLE_DATE de MVJ, c'est purement génial:

Http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=61519

Une fois que vous implémentez cela, passez simplement la date de début et de fin et vous pouvez insérer toutes les dates entre.

2
répondu JonH 2011-10-19 16:41:48

Voici une solution qui ne nécessite pas de récursivité, et en même temps, cette fonction à valeur de table est réutilisable dans de nombreuses requêtes sans avoir besoin de répéter la déclaration des variables standard. C'est la seule alternative, pour ceux qui ne veulent pas de récursivité.

Créez cette fonction simple:

CREATE FUNCTION [dbo].[GenerateDateRange]
(@StartDate AS DATE,
 @EndDate AS   DATE,
 @Interval AS  INT
)
RETURNS @Dates TABLE(DateValue DATE)
AS
BEGIN
    DECLARE @CUR_DATE DATE
    SET @CUR_DATE = @StartDate
    WHILE @CUR_DATE <= @EndDate BEGIN
        INSERT INTO @Dates VALUES(@CUR_DATE)
        SET @CUR_DATE = DATEADD(DAY, @Interval, @CUR_DATE)
    END
    RETURN;
END;

, puis sélectionnez par:

select *
from dbo.GenerateDateRange('2017-01-03', '2017-12-01', 1)
2
répondu sken130 2017-02-11 08:03:02

En utilisant la réponse de @Abe Miesler, pour la commodité des autres, je l'ai intégré dans un TVF pour SQL Server 2008. Cela peut aider les autres-j'ai dû trouver un moyen d'inclure le CTE dans le TVF!

    --Generate a range of dates with interval option, courtesy of Abe Miessler for the core query here!
ALTER FUNCTION [dbo].[DateRange]
(@startDate AS DATE,
 @EndDate AS   DATE,
 @interval AS  INT
)
RETURNS @Dates TABLE(dateValue DATE)
AS
     BEGIN
         WITH Dates
              AS (
              SELECT [Date] = CONVERT( DATETIME, @startDate)
              UNION ALL
              SELECT [Date] = DATEADD(DAY, ISNULL(@interval, 1), [Date])
              FROM Dates
              WHERE Date < @EndDate)
              INSERT INTO @Dates
                     SELECT [Date]
                     FROM Dates
                     OPTION(MAXRECURSION 900);
         RETURN;
     END;
0
répondu Richard Griffiths 2016-08-12 10:07:18
Declare @StartDate datetime = '2015-01-01'
Declare @EndDate datetime = '2016-12-01'
declare @DaysInMonth int
declare @tempDateRange Table
(
DateFrom datetime,
DateThru datetime
);

While @StartDate<=@EndDate
begin
    SET @DaysInMonth=DAY(DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,-1,@StartDate),0)))

    IF DAY(@StartDate)=1 
        SET @EndDate=DATEADD(DAY,14,@StartDate)
    ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=30
        SET @EndDate=DATEADD(DAY,14,@StartDate)
    ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=31
        SET @EndDate=DATEADD(DAY,15,@StartDate)
    ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=28
        SET @EndDate=DATEADD(DAY,12,@StartDate)
    ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=29
        SET @EndDate=DATEADD(DAY,13,@StartDate)

    INSERT INTO @tempDateRange (DateFrom,DateThru)
    VALUES 
     (
        @StartDate,
        @EndDate
     )

    SET @StartDate=DATEADD(DAY,1,@EndDate)

    IF @EndDate< '2016-12-31'
     IF DAY(@StartDate)=1 
        SET @EndDate=DATEADD(DAY,14,@StartDate)
     ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=30
        SET @EndDate=DATEADD(DAY,14,@StartDate)
     ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=31
        SET @EndDate=DATEADD(DAY,15,@StartDate)
     ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=28
        SET @EndDate=DATEADD(DAY,12,@StartDate)
     ELSE IF DAY(@StartDate)=16 AND @DaysInMonth=29
        SET @EndDate=DATEADD(DAY,13,@StartDate)
end ;

select * from @tempDateRange

+++++++++++++++++++++++++++++
Result:
DateFrom |DateThru
0
répondu SanH 2017-01-13 19:25:54

Si pour quelque raison vous ne pouvez pas declare variables, telles que lors de l'utilisation de tables dérivées dans Looker, vous pouvez aller comme ceci:

select
  dateadd(day, nbr - 1, convert(date, '2017-01-01')) as d
from (
  select row_number() over (order by c.object_id) as nbr from sys.columns c
) nbrs
where
  nbr - 1 <= datediff(
    day,
    convert(date, '2017-01-01'),
    convert(date, '2018-12-31')
  )

En passant, voici comment votre vue Date series pourrait ressembler à LookerML:

view: date_series {
  derived_table: {
    sql:
      select
        dateadd(day, nbr - 1, convert(date, '2017-01-01')) as d
      from (
        select row_number() over (order by c.object_id) as nbr from sys.columns c
      ) nbrs
      where
        nbr - 1 <= datediff(day, convert(date, '2017-01-01'), convert(date, '2018-12-31')) ;;
  }

  dimension: date {
    primary_key: yes
    type: date
    sql: ${TABLE}.d ;;
  }
}
0
répondu Lars Blumberg 2018-02-11 19:17:30