web-dev-qa-db-fra.com

Générer des dates entre des périodes

Je dois remplir une table qui stockera les plages de dates entre 2 dates données: 09/01/11 - 10/10/11

Ainsi, dans ce cas, la table commencerait à partir du 01/09/11 et serait stockée chaque jour jusqu'au 10/10/11 Je me demandais s'il y avait une manière astucieuse de faire cela dans SQL Server - j'utilise actuellement SQL Server 2008. Merci

29
Nate Pet

Facile sur SQL 2005+; plus facile si vous avez une table de chiffres ou de pointage. Je l'ai truqué 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écursion.

29
Stuart Ainsworth

Essayez ceci si vous utilisez SQL Server 2005 ou une version plus récente:

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 choses intéressantes que vous pouvez faire avec un CTE. 

33
Abe Miessler

- 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
sll

Voici une solution qui ne nécessite pas de récursivité, et en même temps, cette fonction table est réutilisable dans de nombreuses requêtes sans qu'il soit nécessaire de répéter la déclaration de 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;

Et puis sélectionnez par:

select *
from dbo.GenerateDateRange('2017-01-03', '2017-12-01', 1)
2
sken130

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 avez implémenté cela, il suffit de passer les dates de début et de fin et vous pouvez insérer toutes les dates entre les deux.

2
JonH

À l'aide de la réponse de @Abe Miesler, pour plus de commodité, je l'ai intégrée dans un fichier TVF pour SQL Server 2008. Cela peut aider les autres - je devais trouver un moyen d'inclure le CTE dans la 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
Richard Griffiths
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
SanH

Si, pour une raison quelconque, vous ne pouvez pas utiliser les variables declare, comme lorsque vous utilisez tables dérivées dans Looker , vous pouvez procéder comme suit:

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

À propos, voici à quoi ressemblerait votre vue série de dates dans 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
Lars Blumberg