63 votes

Générer un jeu de résultats d'incrémentation de dates dans TSQL

Envisager la nécessité de créer un jeu de résultats de dates. Nous avons de début et dates de fin, et nous tenons à générer une liste de dates entre les deux.

DECLARE  @Start datetime
         ,@End  datetime
DECLARE @AllDates table
        (@Date datetime)

SELECT @Start = 'Mar 1 2009', @End = 'Aug 1 2009'

--need to fill @AllDates. Trying to avoid looping. 
-- Surely if a better solution exists.

Évaluer la mise en œuvre, en WHILE boucle:

DECLARE @dCounter datetime
SELECT @dCounter = @Start
WHILE @dCounter <= @End
BEGIN
 INSERT INTO @AllDates VALUES (@dCounter)
 SELECT @dCounter=@dCounter+1 
END

Question: Comment voulez-vous créer un ensemble de dates qui sont à l'intérieur d'une plage définie par l'utilisateur à l'aide de T-SQL? Supposons SQL 2005+. Si votre réponse est à l'aide de SQL 2008, veuillez marque en tant que telle.

59voto

devio Points 22981

Si vos dates ne sont plus de 2047 jours d'intervalle:

declare @dt datetime, @dtEnd datetime
set @dt = getdate()
set @dtEnd = dateadd(day, 100, @dt)

select dateadd(day, number, @dt)
from 
    (select distinct number from master.dbo.spt_values
     where name is null
    ) n
where dateadd(day, number, @dt) < @dtEnd

47voto

OMG Ponies Points 144785

Lle-ci utilise une expression de table commune récursive (SQL Server 2005+):

WITH dates AS (
     SELECT CAST('2009-01-01' AS DATETIME) 'date'
     UNION ALL
     SELECT DATEADD(dd, 1, t.date) 
       FROM dates t
      WHERE DATEADD(dd, 1, t.date) <= '2009-02-01')
SELECT ...
  FROM TABLE t
  JOIN dates d ON d.date = t.date --etc.

7voto

Chadwick Points 6302

@KM de réponse crée un tableau de nombres premiers, et l'utilise pour sélectionner une plage de dates. Pour faire la même chose sans le temporaire table de nombres:

DECLARE  @Start datetime
		 ,@End  datetime
DECLARE @AllDates table
		(Date datetime)

SELECT @Start = 'Mar 1 2009', @End = 'Aug 1 2009';

WITH Nbrs_3( n ) AS ( SELECT 1 UNION SELECT 0 ),
     Nbrs_2( n ) AS ( SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2 ),
     Nbrs_1( n ) AS ( SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2 ),
     Nbrs_0( n ) AS ( SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2 ),
     Nbrs  ( n ) AS ( SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2 )

	SELECT @Start+n-1 as Date
		FROM ( SELECT ROW_NUMBER() OVER (ORDER BY n)
			FROM Nbrs ) D ( n )
	WHERE n <= DATEDIFF(day,@Start,@End)+1 ;

Test bien sûr, si vous le faites souvent, une table permanente, peut-être plus performant.

La requête ci-dessus est une version modifiée de cet article, qui traite de la génération de séquences et donne de nombreuses méthodes possibles. J'ai bien aimé celui-ci car il ne permet pas de créer une table temporaire, et n'est pas limité au nombre d'éléments dans l' sys.objects table.

5voto

KM. Points 51800

Pour que cette méthode fonctionne, vous devez faire cette fois une table de configuration:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)

Une fois que les Nombres de la table est mis en place, utilisez cette requête:

SELECT
    @Start+Number-1
    FROM Numbers
    WHERE Number<=DATEDIFF(day,@Start,@End)+1

pour les capturer à faire:

DECLARE  @Start datetime
         ,@End  datetime
DECLARE @AllDates table
        (Date datetime)

SELECT @Start = 'Mar 1 2009', @End = 'Aug 1 2009'

INSERT INTO @AllDates
        (Date)
    SELECT
        @Start+Number-1
        FROM Numbers
        WHERE Number<=DATEDIFF(day,@Start,@End)+1

SELECT * FROM @AllDates

sortie:

Date
-----------------------
2009-03-01 00:00:00.000
2009-03-02 00:00:00.000
2009-03-03 00:00:00.000
2009-03-04 00:00:00.000
2009-03-05 00:00:00.000
2009-03-06 00:00:00.000
2009-03-07 00:00:00.000
2009-03-08 00:00:00.000
2009-03-09 00:00:00.000
2009-03-10 00:00:00.000
....
2009-07-25 00:00:00.000
2009-07-26 00:00:00.000
2009-07-27 00:00:00.000
2009-07-28 00:00:00.000
2009-07-29 00:00:00.000
2009-07-30 00:00:00.000
2009-07-31 00:00:00.000
2009-08-01 00:00:00.000

(154 row(s) affected)

4voto

Kapil Points 95

Essayez ceci. Pas de Boucle, CTE de limites, etc. et vous pourriez avoir à peu près tout pas. de documents générés. Gérer la croix-jointure et de haut en fonction de ce qui est requis.

select top 100000 dateadd(d,incr,'2010-04-01') as dt from
(select  incr = row_number() over (order by object_id, column_id), * from
(
select a.object_id, a.column_id from  sys.all_columns a cross join sys.all_columns b
) as a
) as b

Veuillez noter que l'imbrication est pour faciliter le contrôle et la conversion en points de vue, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X