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
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é.
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.
-- 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
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.
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)
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;
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
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 ;;
}
}