Comment obtenir les dates entre deux dates?
J'ai une variable @MAXDATE
qui stocke la date maximum de la table. Maintenant, je veux obtenir toutes les dates entre @Maxdate
et GETDATE()
et je veux les stocker dans un curseur.
Jusqu'ici j'ai fait comme suit:
;with GetDates As
(
select DATEADD(day,1,@maxDate) as TheDate
UNION ALL
select DATEADD(day,1, TheDate) from GetDates
where TheDate < GETDATE()
)
Cela fonctionne parfaitement, mais lorsque je tente de stocker ces valeurs dans un curseur
SET @DateCurSor=CURSOR FOR
SELECT TheDate
FROM GetDates
Erreur de compilation
Syntaxe incorrecte près du mot clé 'SET'.
Comment résoudre ce problème.
Merci d'avance
Ma première suggestion serait d'utiliser votre table de calendrier , si vous n'en avez pas, créez-en une. Ils sont très utiles. Votre requête est alors aussi simple que:
DECLARE @MinDate DATE = '20140101',
@MaxDate DATE = '20140106';
SELECT Date
FROM dbo.Calendar
WHERE Date >= @MinDate
AND Date < @MaxDate;
Si vous ne voulez pas ou ne pouvez pas créer de table de calendrier, vous pouvez toujours le faire à la volée sans CTE récursif:
DECLARE @MinDate DATE = '20140101',
@MaxDate DATE = '20140106';
SELECT TOP (DATEDIFF(DAY, @MinDate, @MaxDate) + 1)
Date = DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, @MinDate)
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
Pour plus d'informations à ce sujet, voir:
En ce qui concerne l'utilisation de cette séquence de dates dans un curseur, je vous recommanderais vraiment de trouver un autre moyen. Il existe généralement une alternative basée sur un ensemble qui fonctionnera beaucoup mieux.
Donc, avec vos données:
date | it_cd | qty
24-04-14 | i-1 | 10
26-04-14 | i-1 | 20
Pour obtenir la quantité le 28-04-2014 (si je suppose que vous en avez besoin), vous n'avez en réalité besoin d'aucun de ces éléments, vous pouvez simplement utiliser:
SELECT TOP 1 date, it_cd, qty
FROM T
WHERE it_cd = 'i-1'
AND Date <= '20140428'
ORDER BY Date DESC;
Si vous ne le souhaitez pas pour un article particulier:
SELECT date, it_cd, qty
FROM ( SELECT date,
it_cd,
qty,
RowNumber = ROW_NUMBER() OVER(PARTITION BY ic_id
ORDER BY date DESC)
FROM T
WHERE Date <= '20140428'
) T
WHERE RowNumber = 1;
Vous pouvez utiliser ce script pour trouver des dates entre deux dates. Référence extraite de cet article:
DECLARE @StartDateTime DATETIME
DECLARE @EndDateTime DATETIME
SET @StartDateTime = '2015-01-01'
SET @EndDateTime = '2015-01-12';
WITH DateRange(DateData) AS
(
SELECT @StartDateTime as Date
UNION ALL
SELECT DATEADD(d,1,DateData)
FROM DateRange
WHERE DateData < @EndDateTime
)
SELECT DateData
FROM DateRange
OPTION (MAXRECURSION 0)
GO
Créez facilement une fonction de valeur de table qui renverra une table avec toutes les dates . Entrez les dates sous forme de chaîne Vous pouvez personnaliser la date dans le format de votre choix "01/01/2017" -01-2017 'en formats de chaîne (103,126 ...)
Essaye ça
CREATE FUNCTION [dbo].[DateRange_To_Table] ( @minDate_Str NVARCHAR(30), @maxDate_Str NVARCHAR(30))
RETURNS @Result TABLE(DateString NVARCHAR(30) NOT NULL, DateNameString NVARCHAR(30) NOT NULL)
AS
begin
DECLARE @minDate DATETIME, @maxDate DATETIME
SET @minDate = CONVERT(Datetime, @minDate_Str,103)
SET @maxDate = CONVERT(Datetime, @maxDate_Str,103)
INSERT INTO @Result(DateString, DateNameString )
SELECT CONVERT(NVARCHAR(10),@minDate,103), CONVERT(NVARCHAR(30),DATENAME(dw,@minDate))
WHILE @maxDate > @minDate
BEGIN
SET @minDate = (SELECT DATEADD(dd,1,@minDate))
INSERT INTO @Result(DateString, DateNameString )
SELECT CONVERT(NVARCHAR(10),@minDate,103), CONVERT(NVARCHAR(30),DATENAME(dw,@minDate))
END
return
end
Pour exécuter la fonction, procédez comme suit:
SELECT * FROM dbo.DateRange_To_Table ('01/01/2017','31/01/2017')
La sortie sera
01/01/2017 Sunday
02/01/2017 Monday
03/01/2017 Tuesday
04/01/2017 Wednesday
05/01/2017 Thursday
06/01/2017 Friday
07/01/2017 Saturday
08/01/2017 Sunday
09/01/2017 Monday
10/01/2017 Tuesday
11/01/2017 Wednesday
12/01/2017 Thursday
13/01/2017 Friday
14/01/2017 Saturday
15/01/2017 Sunday
16/01/2017 Monday
17/01/2017 Tuesday
18/01/2017 Wednesday
19/01/2017 Thursday
20/01/2017 Friday
21/01/2017 Saturday
22/01/2017 Sunday
23/01/2017 Monday
24/01/2017 Tuesday
25/01/2017 Wednesday
26/01/2017 Thursday
27/01/2017 Friday
28/01/2017 Saturday
29/01/2017 Sunday
30/01/2017 Monday
31/01/2017 Tuesday
Vous pouvez essayer ceci:
SET LANGUAGE SPANISH
DECLARE @startDate DATE = GETDATE() -- Your start date
DECLARE @endDate DATE = DATEADD(MONTH, 16, GETDATE()) -- Your end date
DECLARE @years INT = YEAR(@endDate) - YEAR(@startDate)
CREATE TABLE #TMP_YEARS (
[year] INT
)
-- Get all posible years between the start and end date
WHILE @years >= 0
BEGIN
INSERT INTO #TMP_YEARS
([year])
SELECT YEAR(@startDate) + @years
SET @years = @years - 1
END
;WITH [days]([day]) AS -- Posible days at a month
(
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL -- days lower than 10
SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15 UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18 UNION ALL SELECT 19 UNION ALL -- days lower than 20
SELECT 20 UNION ALL SELECT 21 UNION ALL SELECT 22 UNION ALL SELECT 23 UNION ALL SELECT 24 UNION ALL SELECT 25 UNION ALL SELECT 26 UNION ALL SELECT 27 UNION ALL SELECT 28 UNION ALL SELECT 29 UNION ALL -- days lower than 30
SELECT 30 UNION ALL SELECT 31 -- days higher 30
),
[months]([month]) AS -- All months at a year
(
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12
)
SELECT CONVERT(VARCHAR, a.[year]) + '-' + REPLICATE('0', 2 - LEN(CONVERT(VARCHAR, n.[month]))) + CONVERT(VARCHAR, n.[month]) + '-' + REPLICATE('0', 2 - LEN(CONVERT(VARCHAR, d.[day]))) + CONVERT(VARCHAR, d.[day]) as [date]
FROM #TMP_YEARS a
CROSS JOIN [months] n -- Join all years with all months
INNER JOIN [days] d on DAY(EOMONTH(CONVERT(VARCHAR, a.[year]) + '-' + REPLICATE('0', 2 - LEN(CONVERT(VARCHAR, n.[month]))) + CONVERT(VARCHAR, n.[month]) + '-' + CONVERT(VARCHAR, DAY(EOMONTH(CAST(CONVERT(VARCHAR, a.[year]) + '-' + CONVERT(varchar, n.[month]) + '-15' AS DATE)))))) >= d.[day] AND -- The number of the day can't be higher than the last day of the current month and the current year
CONVERT(VARCHAR, a.[year]) + '-' + REPLICATE('0', 2 - LEN(CONVERT(VARCHAR, n.[month]))) + CONVERT(VARCHAR, n.[month]) + '-' + REPLICATE('0', 2 - LEN(CONVERT(VARCHAR, d.[day]))) + CONVERT(VARCHAR, d.[day]) <= ISNULL(@endDate, GETDATE()) AND -- The current date can't be higher than the end date
CONVERT(VARCHAR, a.[year]) + '-' + REPLICATE('0', 2 - LEN(CONVERT(VARCHAR, n.[month]))) + CONVERT(VARCHAR, n.[month]) + '-' + REPLICATE('0', 2 - LEN(CONVERT(VARCHAR, d.[day]))) + CONVERT(VARCHAR, d.[day]) >= ISNULL(@startDate, GETDATE()) -- The current date should be higher than the start date
ORDER BY a.[year] ASC, n.[month] ASC, d.[day] ASC
La sortie sera quelque chose comme ça, vous pouvez formater la date comme vous le souhaitez:
2019-01-24
2019-01-25
2019-01-26
2019-01-27
2019-01-28
2019-01-29
2019-01-30
2019-01-31
2019-02-01
2019-02-02
2019-02-03
2019-02-04
2019-02-05
2019-02-06
2019-02-07
2019-02-08
2019-02-09
...
C'est la méthode que j'utiliserais.
DECLARE
@DateFrom DATETIME = GETDATE(),
@DateTo DATETIME = DATEADD(HOUR, -1, GETDATE() + 2); -- Add 2 days and minus one hour
-- Dates spaced a day apart
WITH MyDates (MyDate)
AS (
SELECT @DateFrom
UNION ALL
SELECT DATEADD(DAY, 1, MyDate)
FROM MyDates
WHERE MyDate < @DateTo
)
SELECT
MyDates.MyDate
, CONVERT(DATE, MyDates.MyDate) AS [MyDate in DATE format]
FROM
MyDates;
Voici un exemple similaire, mais cette fois-ci, les dates sont espacées d'une heure pour mieux comprendre le fonctionnement de la requête:
-- Alternative example with dates spaced an hour apart
WITH MyDates (MyDate)
AS (SELECT @DateFrom
UNION ALL
SELECT DATEADD(HOUR, 1, MyDate)
FROM MyDates
WHERE MyDate < @DateTo
)
SELECT
MyDates.MyDate
FROM
MyDates;
Comme vous pouvez le constater, la requête est rapide, précise et polyvalente.
create procedure [dbo].[p_display_dates](@startdate datetime,@enddate datetime)
as
begin
declare @mxdate datetime
declare @indate datetime
create table #daterange (dater datetime)
insert into #daterange values (@startdate)
set @mxdate = (select MAX(dater) from #daterange)
while @mxdate < @enddate
begin
set @indate = dateadd(day,1,@mxdate)
insert into #daterange values (@indate)
set @mxdate = (select MAX(dater) from #daterange)
end
select * from #daterange
end
Cela peut être considéré comme un peu compliqué, car dans ma situation, je ne peux pas utiliser de table CTE, alors j'ai décidé de rejoindre "sys.all_objects", puis de créer des numéros de ligne et de les ajouter à la date de début jusqu'à la fin.
Consultez le code ci-dessous où j'ai généré toutes les dates en juillet 2018. Remplacez les dates codées en dur par vos propres variables (testé dans SQL Server 2016):
select top (datediff(dd, '2018-06-30', '2018-07-31')) ROW_NUMBER()
over(order by a.name) as SiNo,
Dateadd(dd, ROW_NUMBER() over(order by a.name) , '2018-06-30') as Dt from sys.all_objects a
Juste en disant ... voici une approche plus simple à cela:
declare @sdate date = '2017-06-25'
, @edate date = '2017-07-24'
; with dates_CTE (date) as (
select @sdate
Union ALL
select DATEADD(day, 1, date)
from dates_CTE
where date < @edate
) select
*
from dates_CTE
J'ai énuméré les dates de 2 semaines plus tard. Vous pouvez utiliser la fonction variable @period OR
declare @period INT, @date_start datetime, @date_end datetime, @i int;
set @period = 14
set @date_start = convert(date,DATEADD(D, -@period, curent_timestamp))
set @date_end = convert(date,current_timestamp)
set @i = 1
create table #datesList(dts datetime)
insert into #datesList values (@date_start)
while @i <= @period
Begin
insert into #datesList values (dateadd(d,@i,@date_start))
set @i = @i + 1
end
select cast(dts as DATE) from #datesList
Drop Table #datesList