I want to produce sequence of dates since given date until today using one select command. It is possible?
WITH DATES_CTE AS (
SELECT TOP 100000
ROW_NUMBER() OVER (ORDER BY a.object_id) - 1 AS DayNumber
FROM
sys.all_columns a
CROSS JOIN
sys.all_columns b)
SELECT
DATEADD(DAY, DayNumber, 0) AS DateValue
FROM
DATES_CTE
WHERE
DATEADD(DAY, DayNumber, 0) >= '2016-01-01'
AND DATEADD(DAY, DayNumber, 0) < '2016-05-01';
Try this with CTE.
WITH CTE_DATE
AS
( SELECT CONVERT(DATE,'2015-01-01') AS CDATE
UNION ALL
SELECT DATEADD(DAY,1,CDATE)
FROM CTE_DATE
WHERE DATEADD(DAY,1,CDATE) <= GETDATE()
)
SELECT * FROM CTE_DATE
option (maxrecursion 0) -- for unlimited recursion
You can use the option option (maxrecursion 0) to avoid the limit recursion.
CREATE TABLE #date (datevalues date)
DECLARE #mindate DATE = '2015-01-01',
#maxdate DATE = GETDATE()
WHILE #mindate <= #maxdate
BEGIN
INSERT INTO
#date (datevalues)
SELECT #mindate
SELECT #mindate = dateadd(dd,1,#mindate)
END
GO
SELECT *FROM #date
GO
DROP TABLE #date
GO
Related
I want to add 30 consecutive days of data in my Date Dimension table using DATEDIFF() but I am getting blank result. Can you please help me correct the code below to get the desired result?
CREATE TABLE dbo.dateDimension (
DateKey INT NOT NULL
,DateValue DATE NOT NULL
,CYear SMALLINT NOT NULL
,CMonth TINYINT NOT NULL
,CONSTRAINT PK_DimDate PRIMARY KEY ( DateKey )
);
GO
CREATE PROC dbo.dateTest
#StartDate DATETIME
AS
WHILE (DATEDIFF(day, #StartDate, GETDATE()) <=30)
BEGIN
INSERT into dbo.dateDimension
SELECT CAST( YEAR(#StartDate) * 10000 + MONTH(#StartDate) * 100 + DAY(#StartDate) AS INT)
,#StartDate
,YEAR(#StartDate)
,MONTH(#StartDate)
SET #StartDate = DATEADD(d,1,#StartDate)
END;
GO
EXECUTE dbo.dateTest '2010-01-01'
SELECT * FROM dbo.dateDimension
The issue is that this logic:
DATEDIFF(day, #StartDate, GETDATE())
gives 3739 days with your current start date, so its never less than 30. Personally I would simply count it as follows:
DECLARE #StartDate DATETIME = '2010-01-01', #Count INT = 0;
WHILE #Count <= 30 BEGIN
INSERT into dbo.dateDimension
SELECT CAST( YEAR(#StartDate) * 10000 + MONTH(#StartDate) * 100 + DAY(#StartDate) AS INT)
, #StartDate
, YEAR(#StartDate)
, MONTH(#StartDate);
SET #StartDate = DATEADD(d,1,#StartDate);
set #Count = #Count + 1;
END;
SELECT *
FROM dbo.dateDimension;
If you are using SQL Server 2016 or above, this solution will not use a while loop, instead it uses a CTE to generate 30 rows numbered I to 30 and then uses the date to convert to yyyymmdd.
DECLARE #NUM_DAYS INT=30;
DECLARE #STARTDATE DATETIME='2020-01-01';
WITH CTE AS(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS SRL
FROM STRING_SPLIT(REPLICATE(',',#num_days-1), ',') AS A
)
INSERT INTO dbo.dateDimension
SELECT
CONVERT(INT, CONVERT(CHAR(8), DATEADD(DAY, SRL-1, #STARTDATE), 112))
, #STARTDATE
, YEAR(#STARTDATE)
, MONTH(#STARTDATE)
FROM CTE
SELECT * FROM dbo.dateDimension
I have a situation where querying a datetime2(7) field with GETDATE()-n is not returning expected output.
Query with >= GEDATE()-20 returns all dates excluding 4/27 (if run today 5/17)
Query with >= 4/27/2018 returns all dates including 4/27.
Is it something to do with the timepart? even if the timepart is all 0's?
DECLARE #MinDate DATE = '04-01-2018',
#MaxDate DATE = '05-17-2018';
SELECT TOP (DATEDIFF(DAY, #MinDate, #MaxDate) + 1)
DateCol = CAST(DATEADD(DAY, ROW_NUMBER() OVER(ORDER BY a.object_id) - 1, #MinDate) AS DATETIME2(7))
INTO #temp
FROM sys.all_objects a
CROSS JOIN sys.all_objects b;
--SELECT * FROM #temp
SELECT COUNT(*) FROM #temp WHERE DateCol >= GETDATE()-20
SELECT COUNT(*) FROM #temp WHERE DateCol >= '2018-04-27' --excludes the date 4/27
/*
SELECT * FROM #temp WHERE DateCol >= GETDATE()-20 --Excludes 4/27
SELECT * FROM #temp WHERE DateCol >= '2018-04-27' --Expected output includes 4/27
*/
DROP TABLE #temp
This is due to '2018-04-27 00:00:00.0000000' not greater than GETDATE()-20.
GETDATE()-20 will give something like '2018-04-27 10:25:37.680'
For one case you are using only date and for the other scenario it is date and time.
You should change your query like following to change the date-time to date before comparing to get the desired output.
SELECT COUNT(*) FROM #temp WHERE DateCol >= cast(GETDATE() -20 as date)
I have 2 dates 01/04/2017 and 30/04/2017. I want all the dates between these 2 dates with 7 days interval.
Expected Output :
01/04/2017
08/04/2017
15/04/2017
22/04/2017
29/04/2017
Please help!!
DECLARE #StartDate DATETIME,
#EndDate DATETIME
SELECT #StartDate = '2017-04-01',
#EndDate = '2017-04-30'
SELECT DATEADD(DAY, number*7, #StartDate)
FROM master.dbo.spt_values
WHERE type='P'
AND #EndDate >= DATEADD(DAY, number*7, #StartDate)
One method would be to use a Calendar table. Then return the results from there using the modulus to get the 7th rows:
WITH Dates AS(
SELECT *,
ROW_NUMBER() OVER (ORDER BY [date]) AS RN
FROM DateTable
WHERE [Date] BETWEEN '20170401' AND '20170430')
SELECT *
FROM Dates
WHERE (RN - 1) % 7 = 0;
I've used this solution, as from your post you imply that you might supply any date range, and that the 1st day may not necessarily be a Monday (or other specific day).
Try this
DECLARE #STRT DATETIME='04/01/2017',#END DATETIME ='04/30/2017'
;WITH CTE
AS
(
SELECT
MyDate = CAST(#STRT AS DATETIME)
UNION ALL
SELECT
MyDate = CAST(MyDate AS DATETIME)+7
FROM CTE
WHERE CAST(MyDate AS DATETIME)+7 < CAST(#END AS DATETIME)
)
SELECT
*
FROM CTE
result
Declare #StartDate DATE=CONVERT(DATE,'01/04/2017',104),#EndDate DATE=CONVERT(DATE,'01/12/2017',104)
Declare #String NVARCHAR(MAX)=''
WHILE (#StartDate<=#EndDate AND DATEDIFF(wk,#StartDate,#EndDate)>=0)
BEGIN
SET #String=#String+CONVERT(NVARCHAR(100),#StartDate)+CHAR(10)+CHAR(13)
SET #StartDate=DATEADD(d,7,#StartDate)
END
PRINT #String
GO
I have two specific dates.
lets say from 2014-04-04 To 2015-10-04.
I have a plan that says classes of Blah course will be on mon, wed and Fri.
Now I want to get the dates of each mon, wed and Fri from 2014-04-04 to 2015-10-04.
With a calendar table it is simple:
SELECT t.*
FROM dbo.TableName t
INNER JOIN CalendarTable c
ON t.DateColumn = c.Date
WHERE c.Date between '2014-04-04' AND '2015-10-04'
AND DATEPART(dw, c.Date) IN (1,3,5)
How to generate a calendar table (look for "Calendar table").
The standard reply to this by any seasoned SQL Server veteran, would be to create a calendar table. But all too often this is scoffed. So here's a slow and out-of-the-box method:
DECLARE #startDate DATE = '2014-04-04', #endDate DATE = '2015-10-04';
WITH CTE(N) AS (SELECT 1 FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1))a(N)),
CTE2(N) AS (SELECT 1 FROM CTE x CROSS JOIN CTE y),
CTE3(N) AS (SELECT 1 FROM CTE2 x CROSS JOIN CTE2 y),
CTE4(N) AS (SELECT 1 FROM CTE3 x CROSS JOIN CTE3 y),
CTE5(N) AS (SELECT 1 FROM CTE4 x CROSS JOIN CTE4 y),
CTE6(N) AS (SELECT 0 UNION ALL
SELECT TOP (DATEDIFF(day,#startDate,#endDate))
ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM CTE5),
TALLY(N) AS (SELECT DATEADD(day, N, #startDate)
FROM CTE6
WHERE DATENAME(weekday,DATEADD(day, N, #startDate)) IN ('Monday','Tuesday','Wednesday'))
SELECT N
FROM TALLY
ORDER BY N;
You can use a Recursive CTE if you do not have numbers table. Something like this. Note that the DATEPART(weekday,Dates) IN(1,3,5) is based on your setting of SELECT ##DATEFIRST.
For example If ##DATEFIRST is 1 then use DATEPART(weekday,Dates) IN(1,3,5)
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-04-04'
SET #EndDate = '2015-10-04'
;WITH CTE AS
(
SELECT #StartDate Dates
UNION ALL SELECT DATEADD(d,1,Dates) FROM CTE WHERE DATEADD(d,1,Dates) <=#EndDate
)
SELECT Dates,DATENAME(weekday,Dates) FROM CTE
WHERE DATEPART(weekday,Dates) IN(1,3,5)
OPTION (MAXRECURSION 0);
GO
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-04-04'
SET #EndDate = '2015-10-04'
;WITH CTE AS
(
SELECT #StartDate Dates
UNION ALL SELECT DATEADD(d,1,Dates) FROM CTE WHERE DATEADD(d,1,Dates) <=#EndDate
)
SELECT Dates,DATENAME(weekday,Dates) FROM CTE
WHERE DATEPART(weekday,Dates) IN(1,3,5)
OPTION (MAXRECURSION 0);
GO
--- thanks to #ughai
I've comeup with another way to do this.
this query will not only Show the dates in between but also it will compare the dates u want to compare with.
Q.Dates Comparison
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate = '2014-12-22'
SET #EndDate = '2015-02-13'
drop table #TabCourseDetailID
SELECT ROW_NUMBER() OVER(ORDER BY CourseDetailID asc) AS Row,
CourseDetailID
into #TabCourseDetailID
from coursedetail
where UnitType='T' and courseID =1
Declare #counter as int
Declare #CourseDetailID varchar(500)
set #counter = 0
Declare #TempTable Table (FirstValue datetime,LastValue int)
while #StartDate <= #EndDate
begin
If DATEPART(WeekDay,#StartDate) IN (2,4,6)
begin
Set #Counter = #counter+1
Select #CoursedetailId=CoursedetailId
from #TabCourseDetailID
where row=#counter
insert into #TempTable (FirstValue,LastValue)
values (#StartDate,#CoursedetailId)
end
set #StartDate =DATEADD(d,1,#StartDate)
end
select t.LastValue,
t.FirstValue,
bp.conductedDate
from batchprogress bp
Join #TempTable t on (t.LastValue=bp.CoursedetailID)
where CourseID =1 and batchID =5
order by t.lastvalue
As I have From and To date. Something like below,
BeginDate End Date
1989-01-01 00:00:00.000 2015-12-31 00:00:00.000
I need to loop through until i get the list of all the Date's between those 2 (Begin & End Date's) records. I need to know what will be the efficient way of doing this. I have no clue on how to do this. Any help to this will be highly appreciated.
Thanks
This method uses a generated numbers table and is probably faster than looping.
DECLARE #BeginDate DATETIME = '19890101';
DECLARE #EndDate DATETIME = '20151231';
WITH
E1(N) AS ( SELECT 1 FROM ( VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) DT(N)),
E2(N) AS ( SELECT 1 FROM E1 A, E1 B),
E4(N) AS ( SELECT 1 FROM E2 A, E2 B),
Numbers(N) AS
(
SELECT ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL)) - 1 FROM E4
)
SELECT
N,
DATEADD(D, N, #BeginDate) AS TheDate
FROM Numbers
WHERE N <= DATEDIFF(D, #BeginDate, #EndDate)
You can do this with WHILE loop:
DECLARE #sdt DATE = '1989-01-01'
DECLARE #edt DATE = '2015-12-31'
WHILE #sdt <= #edt
BEGIN
PRINT #sdt
SET #sdt = DATEADD(dd, 1, #sdt )
END
Or with recursive CTE:
DECLARE #sdt DATE = '1989-01-01'
DECLARE #edt DATE = '2015-12-31';
WITH cte
AS ( SELECT #sdt AS sdt
UNION ALL
SELECT DATEADD(dd, 1, sdt)
FROM cte
WHERE DATEADD(dd, 1, sdt) <= #edt
)
SELECT *
FROM cte
OPTION ( MAXRECURSION 10000 )
There is also tally table method as in link provided by #Bridge
Actually the answer is tally tables. But if there is not a big interval the difference will be insignificant.
Something like this should work for your purposes:
DECLARE #sd date = '1989-01-01 00:00:00.000'
, #ed date = '2015-12-31 00:00:00.000'
DECLARE #tt TABLE(
[Date] date
)
WHILE(#sd <= #ed) --Loop which checks each iteration if the date has reached the end
BEGIN
INSERT INTO #tt
SELECT #sd AS Date
SET #sd = DATEADD(dd,1,#sd) --This willl increment the date so you actually advance the loop
END
SELECT * FROM #tt