Struggling a bit with this...
I have a table with the following columns:
Type varchar
StartDate datetime
EndDate datetime
Interval int
What I want is a results table with the type column and all the dates between the start date and end date, using the interval as month breaks between them.
For instance if the only row in my table is:
'Test', '2017-01-01', '2019-01-01', 6
I want a results table that has 5 rows, with 'Test' as the Type on every row, and a date column that goes from:
'2017-01-01',
'2017-07-01',
'2018-01-01',
etc.
I've created a Calendar table and even a DateRange function where I pass in a start date, end date and month interval which returns me all the dates I'd want, but since it's a table-valued function I don't seem to be able to call it with data from another table.
How do I do this?
Thanks.
I'll often use a TVF to create dynamic Date/Time Ranges. A tally/calendar table will do the trick as well, but the UDF offers some additional functionality. For example, you supply the Range, DatePart and Increment
Declare #YourTable table ([Type] varchar(25),StartDate date,EndDate date,Interval int)
Insert Into #YourTable values
('Test','2017-01-01','2019-01-01', 6)
Select A.[Type]
,B.*
From #YourTable A
Cross Apply [dbo].[udf-Range-Date](A.StartDate,A.EndDate,'MM', A.Interval) B
Returns
Type RetSeq RetVal
Test 1 2017-01-01
Test 2 2017-07-01
Test 3 2018-01-01
Test 4 2018-07-01
Test 5 2019-01-01
The UDF if Interested
CREATE FUNCTION [dbo].[udf-Range-Date] (#R1 datetime,#R2 datetime,#Part varchar(10),#Incr int)
Returns Table
Return (
with cte0(M) As (Select 1+Case #Part When 'YY' then DateDiff(YY,#R1,#R2)/#Incr When 'QQ' then DateDiff(QQ,#R1,#R2)/#Incr When 'MM' then DateDiff(MM,#R1,#R2)/#Incr When 'WK' then DateDiff(WK,#R1,#R2)/#Incr When 'DD' then DateDiff(DD,#R1,#R2)/#Incr When 'HH' then DateDiff(HH,#R1,#R2)/#Incr When 'MI' then DateDiff(MI,#R1,#R2)/#Incr When 'SS' then DateDiff(SS,#R1,#R2)/#Incr End),
cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h ),
cte3(N,D) As (Select 0,#R1 Union All Select N,Case #Part When 'YY' then DateAdd(YY, N*#Incr, #R1) When 'QQ' then DateAdd(QQ, N*#Incr, #R1) When 'MM' then DateAdd(MM, N*#Incr, #R1) When 'WK' then DateAdd(WK, N*#Incr, #R1) When 'DD' then DateAdd(DD, N*#Incr, #R1) When 'HH' then DateAdd(HH, N*#Incr, #R1) When 'MI' then DateAdd(MI, N*#Incr, #R1) When 'SS' then DateAdd(SS, N*#Incr, #R1) End From cte2 )
Select RetSeq = N+1
,RetVal = D
From cte3,cte0
Where D<=#R2
)
/*
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS
Syntax:
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1)
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1)
*/
Related
I have below query and i want to get datetime in 30 min intervals between 2 datetime. Basicly I got it, but is limitited and wouln't return al results if the timediff is over 24 hrs.
For example:
#DateTime1 = 24/11/2016 18:00:00
#DateTime2 = 25/11/2016 06:00:00
Result: (in format "dd-HH:mm")
24-18:00
24-18:30
24-19:00
24-19:30
24-20:00
...
...
25-05:00
25-05:30
25-06:00
What I've tried.
SELECT number, DATEADD(MINUTE, number, #DateTime1) AS DateTimeLine, DATEPART(DAY, DATEADD(MINUTE, number, #DateTime1)) AS Days, DATEPART(MONTH,
DATEADD(MINUTE, number, #DateTime1)) AS Months, DATEPART(YEAR, DATEADD(MINUTE, number, #DateTime1)) AS Years, DATEPART(HOUR, DATEADD(MINUTE,
number, #DateTime1)) AS Hours, DATEPART(MINUTE, DATEADD(MINUTE, number, #DateTime1)) AS Minute, CAST(DATEADD(MINUTE, number, #DateTime1)
AS DATE) AS Date, CAST(DATEADD(MINUTE, number, #DateTime1) AS TIME) AS Time
FROM master.dbo.spt_values
WHERE (type = 'P') AND (DATEPART(MINUTE, DATEADD(MINUTE, number, #DateTime1)) = 30 OR DATEPART(MINUTE, DATEADD(MINUTE, number, #DateTime1)) = 0) AND (DATEADD(MINUTE, number, #DateTime1) <= #DateTime2)
ORDER BY number
A tally table is a great way to deal with this type of thing. I keep one in a view to avoid using spt_values.
create View [dbo].[cteTally] as
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), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
Then your code becomes really simple too. A small amount of datemath and voila.
declare #DateTime1 datetime = '2016/11/24 18:00:00'
, #DateTime2 datetime = '2016/11/25 06:00:00'
select FORMAT(DATEADD(minute, (t.N - 1) * 30, #DateTime1), 'dd-HH:mm')
from cteTally t
where t.N <= (DATEDIFF(hour, #DateTime1, #DateTime2) * 2) + 1
I have a TVF which generates dynamic date/time ranges. It is faster than a recursive cte, and I think more flexible. You pass the date range, desired DatePart, and increment.
Declare #DateTime1 DateTime = '2016-11-24 18:00:00'
Declare #DateTime2 DateTime = '2016-11-25 06:00:00'
Select Format(RetVal,'dd-HH:mm') from [dbo].[udf-Range-Date](#DateTime1,#DateTime2,'MI',30)
Returns
24-18:00
24-18:30
24-19:00
24-19:30
24-20:00
24-20:30
24-21:00
24-21:30
24-22:00
24-22:30
24-23:00
24-23:30
25-00:00
....
25-04:30
25-05:00
25-05:30
25-06:00
The UDF if needed
CREATE FUNCTION [dbo].[udf-Range-Date] (#R1 datetime,#R2 datetime,#Part varchar(10),#Incr int)
Returns Table
Return (
with cte0(M) As (Select 1+Case #Part When 'YY' then DateDiff(YY,#R1,#R2)/#Incr When 'QQ' then DateDiff(QQ,#R1,#R2)/#Incr When 'MM' then DateDiff(MM,#R1,#R2)/#Incr When 'WK' then DateDiff(WK,#R1,#R2)/#Incr When 'DD' then DateDiff(DD,#R1,#R2)/#Incr When 'HH' then DateDiff(HH,#R1,#R2)/#Incr When 'MI' then DateDiff(MI,#R1,#R2)/#Incr When 'SS' then DateDiff(SS,#R1,#R2)/#Incr End),
cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h ),
cte3(N,D) As (Select 0,#R1 Union All Select N,Case #Part When 'YY' then DateAdd(YY, N*#Incr, #R1) When 'QQ' then DateAdd(QQ, N*#Incr, #R1) When 'MM' then DateAdd(MM, N*#Incr, #R1) When 'WK' then DateAdd(WK, N*#Incr, #R1) When 'DD' then DateAdd(DD, N*#Incr, #R1) When 'HH' then DateAdd(HH, N*#Incr, #R1) When 'MI' then DateAdd(MI, N*#Incr, #R1) When 'SS' then DateAdd(SS, N*#Incr, #R1) End From cte2 )
Select RetSeq = N+1
,RetVal = D
From cte3,cte0
Where D<=#R2
)
/*
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS
Syntax:
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1)
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1)
*/
using a recursive Common Table Expression [CTE] is one pretty clean method. For the formatting I am showing FORMAT() from SQL-Server 2012+ you may consider using DATEPART etc to do it though as FORMAT() can have performance impact.
I do agree with #RossBush's comment if you do things like this a lot generating a calendar (dates) and a time dimensions is very helpful for these purposes.
DECLARE #DateTime1 DATETIME = '2016/11/24 18:00:00'
DECLARE #DateTime2 DATETIME = '2016/11/25 06:00:00'
;WITH cte30MinIncrements AS (
SELECT #DateTime1 as DT
UNION ALL
SELECT DATEADD(MINUTE,30,DT)
FROM
cte30MinIncrements
WHERE DATEADD(MINUTE,30,DT) <= #DateTime2
)
SELECT
*
,FORMAT(DT,'dd-HH:mm') as Formated
FROM
cte30MinIncrements
Please see if this works.
declare #DateTime1 DateTime = '2016-11-24 18:00:00'
declare #DateTime2 DateTime = '2016-11-25 18:00:00'
declare #Interval DateTime = #DateTime1
declare #vartmptable table(DT DateTime)
While (#Interval < #DateTime2)
begin
--select #Interval, FORMAT(#Interval,'dd-HH:mm')
insert into #vartmptable select #Interval
set #Interval = DATEADD(mi,30,#Interval)
end
select FORMAT(DT,'dd-HH:mm') from #vartmptable
What about this? You can use variables/ fixed values as necessary.
WITH CTE_Numbers
AS (
SELECT n = 1
UNION ALL
SELECT n + 1
FROM CTE_Numbers
WHERE n < 100
)
SELECT FORMAT(DATEADD(mi, n * 30, '2016/11/03'),'dd-HH:mm')
FROM CTE_Numbers
I have table with month's ranges like this:
CREATE TABLE [dbo].[T_month_ranges](
[StartMonth] [datetime] NULL,
[EndMonth] [datetime] NULL
) ON [PRIMARY]
INSERT INTO [dbo].[T_month_ranges] ([StartMonth],[EndMonth]) VALUES
('2015-02-01','2015-04-01')
INSERT INTO [dbo].[T_month_ranges] ([StartMonth],[EndMonth]) VALUES
('2016-12-01','2017-02-01')
INSERT INTO [dbo].[T_month_ranges] ([StartMonth],[EndMonth]) VALUES
('2017-08-01','2017-09-01');
These dates represents only year and month, first day is not important here.
Now we need to create select, that returns all months between dates in this table. So in the query result would be dates like these:
2015-02-01;2015-03-01;2015-04-01;2016-12-01;2017-01-01;2017-02-01;2017-08-01;2017-09-01
What is the best approach to achieve this in sql server ?
You can use a recursive CTE:
with m as (
select mr.startmonth as mon, mr.endmonth
from T_month_ranges mr
union all
select dateadd(month, 1, m.mon), m.endmonth
from m
where m.mon < m.endmonth
)
select m.mon
from m;
If your ranges are really wide (which seems unlikely with months), then you might need to set the MAXRECURSION option to 0.
An alternative -- which is probably faster -- is to use a table of numbers:
with n as (
select row_number() over (order by (select null)) - 1 as n
from master..spt_values
)
select dateadd(month, n.n, mr.startmonth)
from T_month_ranges mr join
n
on dateadd(month, n.n, mr.startmonth) <= mr.endmonth;
I'll often use a TVF to create dynamic date/time ranges. A tally/table would do the trick as well. The function is parameter driven, you supply the Range, DatePart, and Increment
For example:
Select A.*
,B.*
From T_month_ranges A
Cross Apply [dbo].[udf-Range-Date](A.StartMonth,A.EndMonth,'MM',1) B
Returns
The UDF if interested.
CREATE FUNCTION [dbo].[udf-Range-Date] (#R1 datetime,#R2 datetime,#Part varchar(10),#Incr int)
Returns Table
Return (
with cte0(M) As (Select 1+Case #Part When 'YY' then DateDiff(YY,#R1,#R2)/#Incr When 'QQ' then DateDiff(QQ,#R1,#R2)/#Incr When 'MM' then DateDiff(MM,#R1,#R2)/#Incr When 'WK' then DateDiff(WK,#R1,#R2)/#Incr When 'DD' then DateDiff(DD,#R1,#R2)/#Incr When 'HH' then DateDiff(HH,#R1,#R2)/#Incr When 'MI' then DateDiff(MI,#R1,#R2)/#Incr When 'SS' then DateDiff(SS,#R1,#R2)/#Incr End),
cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h ),
cte3(N,D) As (Select 0,#R1 Union All Select N,Case #Part When 'YY' then DateAdd(YY, N*#Incr, #R1) When 'QQ' then DateAdd(QQ, N*#Incr, #R1) When 'MM' then DateAdd(MM, N*#Incr, #R1) When 'WK' then DateAdd(WK, N*#Incr, #R1) When 'DD' then DateAdd(DD, N*#Incr, #R1) When 'HH' then DateAdd(HH, N*#Incr, #R1) When 'MI' then DateAdd(MI, N*#Incr, #R1) When 'SS' then DateAdd(SS, N*#Incr, #R1) End From cte2 )
Select RetSeq = N+1
,RetVal = D
From cte3,cte0
Where D<=#R2
)
/*
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS
Syntax:
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1)
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1)
*/
Option 2 (without a UDF)
Select A.*
,B.*
From T_month_ranges A
Cross Apply (
Select Top (DateDiff(MM,A.Startmonth,A.EndMonth)+1)
Date=DateAdd(MM,Row_Number() over (Order by (Select null)) - 1,A.Startmonth)
From master..spt_values
) B
Can someone help me with getting the first and last day of week based on yearweek integer like 201648 without conserning about setting the ##firstdate attribute. I want iso date starting on monday in datetime format.
declare #yrwk int = 201648
declare #yr int = left(#yrwk,4)
declare #wk int = right(#yrwk,2)
select dateadd (week, #wk, dateadd (year, #yr-1900, 0)) - 4 - datepart(dw, dateadd (week, #wk, dateadd (year, #yr-1900, 0)) - 4) + 1
--returns 11/27/2016 which is Sunday of that week (start of week)
--change +1 to +2 at the end for "Monday"
After a little consideration, I thought that perhaps my dynamic Date/Time Range UDF may help here. I use this UDF to generate dynamic date/time ranges. You can supply the desired date range, date part and increment. A tally table would do the trick as well
In this case, we are getting the Nth Monday regardless of the datepart(WK,..) as per the requirements.
Declare #YYYYWW int = 201648
Select WkNbr = B.RetSeq
,WkBeg = B.RetVal
,WkEnd = DateAdd(DD,6,B.RetVal)
From (
Select MinDate=Min(RetVal)
From [dbo].[udf-Range-Date](DateFromParts(Left(#YYYYWW,4),1,1),DateFromParts(Left(#YYYYWW,4),1,10),'DD',1)
Where DateName(DW,RetVal)='Monday'
) A
Cross Apply (Select * From [dbo].[udf-Range-Date](A.MinDate,DateFromParts(Left(#YYYYWW,4),12,31),'DD',7) ) B
Where B.RetSeq = Right(#YYYYWW,2)
Returns
WkNbr WkBeg WkEnd
48 2016-11-28 2016-12-04
The UDF if interested
CREATE FUNCTION [dbo].[udf-Range-Date] (#R1 datetime,#R2 datetime,#Part varchar(10),#Incr int)
Returns Table
Return (
with cte0(M) As (Select 1+Case #Part When 'YY' then DateDiff(YY,#R1,#R2)/#Incr When 'QQ' then DateDiff(QQ,#R1,#R2)/#Incr When 'MM' then DateDiff(MM,#R1,#R2)/#Incr When 'WK' then DateDiff(WK,#R1,#R2)/#Incr When 'DD' then DateDiff(DD,#R1,#R2)/#Incr When 'HH' then DateDiff(HH,#R1,#R2)/#Incr When 'MI' then DateDiff(MI,#R1,#R2)/#Incr When 'SS' then DateDiff(SS,#R1,#R2)/#Incr End),
cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h ),
cte3(N,D) As (Select 0,#R1 Union All Select N,Case #Part When 'YY' then DateAdd(YY, N*#Incr, #R1) When 'QQ' then DateAdd(QQ, N*#Incr, #R1) When 'MM' then DateAdd(MM, N*#Incr, #R1) When 'WK' then DateAdd(WK, N*#Incr, #R1) When 'DD' then DateAdd(DD, N*#Incr, #R1) When 'HH' then DateAdd(HH, N*#Incr, #R1) When 'MI' then DateAdd(MI, N*#Incr, #R1) When 'SS' then DateAdd(SS, N*#Incr, #R1) End From cte2 )
Select RetSeq = N+1
,RetVal = D
From cte3,cte0
Where D<=#R2
)
/*
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS
Syntax:
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1)
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1)
*/
I have below query and i want to get datetime in 30 min intervals between 2 datetime. Basicly I got it, but is limitited and wouln't return al results if the timediff is over 24 hrs.
For example:
#DateTime1 = 24/11/2016 18:00:00
#DateTime2 = 25/11/2016 06:00:00
Result: (in format "dd-HH:mm")
24-18:00
24-18:30
24-19:00
24-19:30
24-20:00
...
...
25-05:00
25-05:30
25-06:00
What I've tried.
SELECT number, DATEADD(MINUTE, number, #DateTime1) AS DateTimeLine, DATEPART(DAY, DATEADD(MINUTE, number, #DateTime1)) AS Days, DATEPART(MONTH,
DATEADD(MINUTE, number, #DateTime1)) AS Months, DATEPART(YEAR, DATEADD(MINUTE, number, #DateTime1)) AS Years, DATEPART(HOUR, DATEADD(MINUTE,
number, #DateTime1)) AS Hours, DATEPART(MINUTE, DATEADD(MINUTE, number, #DateTime1)) AS Minute, CAST(DATEADD(MINUTE, number, #DateTime1)
AS DATE) AS Date, CAST(DATEADD(MINUTE, number, #DateTime1) AS TIME) AS Time
FROM master.dbo.spt_values
WHERE (type = 'P') AND (DATEPART(MINUTE, DATEADD(MINUTE, number, #DateTime1)) = 30 OR DATEPART(MINUTE, DATEADD(MINUTE, number, #DateTime1)) = 0) AND (DATEADD(MINUTE, number, #DateTime1) <= #DateTime2)
ORDER BY number
A tally table is a great way to deal with this type of thing. I keep one in a view to avoid using spt_values.
create View [dbo].[cteTally] as
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), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
Then your code becomes really simple too. A small amount of datemath and voila.
declare #DateTime1 datetime = '2016/11/24 18:00:00'
, #DateTime2 datetime = '2016/11/25 06:00:00'
select FORMAT(DATEADD(minute, (t.N - 1) * 30, #DateTime1), 'dd-HH:mm')
from cteTally t
where t.N <= (DATEDIFF(hour, #DateTime1, #DateTime2) * 2) + 1
I have a TVF which generates dynamic date/time ranges. It is faster than a recursive cte, and I think more flexible. You pass the date range, desired DatePart, and increment.
Declare #DateTime1 DateTime = '2016-11-24 18:00:00'
Declare #DateTime2 DateTime = '2016-11-25 06:00:00'
Select Format(RetVal,'dd-HH:mm') from [dbo].[udf-Range-Date](#DateTime1,#DateTime2,'MI',30)
Returns
24-18:00
24-18:30
24-19:00
24-19:30
24-20:00
24-20:30
24-21:00
24-21:30
24-22:00
24-22:30
24-23:00
24-23:30
25-00:00
....
25-04:30
25-05:00
25-05:30
25-06:00
The UDF if needed
CREATE FUNCTION [dbo].[udf-Range-Date] (#R1 datetime,#R2 datetime,#Part varchar(10),#Incr int)
Returns Table
Return (
with cte0(M) As (Select 1+Case #Part When 'YY' then DateDiff(YY,#R1,#R2)/#Incr When 'QQ' then DateDiff(QQ,#R1,#R2)/#Incr When 'MM' then DateDiff(MM,#R1,#R2)/#Incr When 'WK' then DateDiff(WK,#R1,#R2)/#Incr When 'DD' then DateDiff(DD,#R1,#R2)/#Incr When 'HH' then DateDiff(HH,#R1,#R2)/#Incr When 'MI' then DateDiff(MI,#R1,#R2)/#Incr When 'SS' then DateDiff(SS,#R1,#R2)/#Incr End),
cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h ),
cte3(N,D) As (Select 0,#R1 Union All Select N,Case #Part When 'YY' then DateAdd(YY, N*#Incr, #R1) When 'QQ' then DateAdd(QQ, N*#Incr, #R1) When 'MM' then DateAdd(MM, N*#Incr, #R1) When 'WK' then DateAdd(WK, N*#Incr, #R1) When 'DD' then DateAdd(DD, N*#Incr, #R1) When 'HH' then DateAdd(HH, N*#Incr, #R1) When 'MI' then DateAdd(MI, N*#Incr, #R1) When 'SS' then DateAdd(SS, N*#Incr, #R1) End From cte2 )
Select RetSeq = N+1
,RetVal = D
From cte3,cte0
Where D<=#R2
)
/*
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS
Syntax:
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1)
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1)
*/
using a recursive Common Table Expression [CTE] is one pretty clean method. For the formatting I am showing FORMAT() from SQL-Server 2012+ you may consider using DATEPART etc to do it though as FORMAT() can have performance impact.
I do agree with #RossBush's comment if you do things like this a lot generating a calendar (dates) and a time dimensions is very helpful for these purposes.
DECLARE #DateTime1 DATETIME = '2016/11/24 18:00:00'
DECLARE #DateTime2 DATETIME = '2016/11/25 06:00:00'
;WITH cte30MinIncrements AS (
SELECT #DateTime1 as DT
UNION ALL
SELECT DATEADD(MINUTE,30,DT)
FROM
cte30MinIncrements
WHERE DATEADD(MINUTE,30,DT) <= #DateTime2
)
SELECT
*
,FORMAT(DT,'dd-HH:mm') as Formated
FROM
cte30MinIncrements
Please see if this works.
declare #DateTime1 DateTime = '2016-11-24 18:00:00'
declare #DateTime2 DateTime = '2016-11-25 18:00:00'
declare #Interval DateTime = #DateTime1
declare #vartmptable table(DT DateTime)
While (#Interval < #DateTime2)
begin
--select #Interval, FORMAT(#Interval,'dd-HH:mm')
insert into #vartmptable select #Interval
set #Interval = DATEADD(mi,30,#Interval)
end
select FORMAT(DT,'dd-HH:mm') from #vartmptable
What about this? You can use variables/ fixed values as necessary.
WITH CTE_Numbers
AS (
SELECT n = 1
UNION ALL
SELECT n + 1
FROM CTE_Numbers
WHERE n < 100
)
SELECT FORMAT(DATEADD(mi, n * 30, '2016/11/03'),'dd-HH:mm')
FROM CTE_Numbers
I have the following MS SQL Server query that returns the SUM at a certain date (2016-06-22) :
SELECT SUM(Value) FROM Sales
WHERE EndDate>='2016-06-22' AND StartDate<'2016-06-22'
I'm trying to display the SUM for every day of a chosen interval.
What I want can be done like this:
SELECT
(SELECT SUM(Value) FROM Sales WHERE EndDate>='2016-06-01' AND StartDate<'2016-06-01'),
(SELECT SUM(Value) FROM Sales WHERE EndDate>='2016-06-02' AND StartDate<'2016-06-02'),
....
(SELECT SUM(Value) FROM Sales WHERE EndDate>='2016-06-30' AND StartDate<'2016-06-30')
I want it to be done in a more elegant way.
I use a UDF to create Dynamic Date Ranges (listed below). You could also use a Numbers or Tally table as will
Select DateR1
,SomeTotal = sum(Value)
From Aales A
Join (Select DateR1=RetVal,DateR2=DateAdd(DD,1,RetVal) from [dbo].[udf-Create-Range-Date]('2016-06-01','2016-06-30','DD',1)) B
on SalesDate Between DateR1 and DateR2 and SalesDate<DateR2
Group By DateR1
Order By DateR1
The UDF
CREATE FUNCTION [dbo].[udf-Create-Range-Date] (#DateFrom datetime,#DateTo datetime,#DatePart varchar(10),#Incr int)
Returns
#ReturnVal Table (RetVal datetime)
As
Begin
With DateTable As (
Select DateFrom = #DateFrom
Union All
Select Case #DatePart
When 'YY' then DateAdd(YY, #Incr, df.dateFrom)
When 'QQ' then DateAdd(QQ, #Incr, df.dateFrom)
When 'MM' then DateAdd(MM, #Incr, df.dateFrom)
When 'WK' then DateAdd(WK, #Incr, df.dateFrom)
When 'DD' then DateAdd(DD, #Incr, df.dateFrom)
When 'HH' then DateAdd(HH, #Incr, df.dateFrom)
When 'MI' then DateAdd(MI, #Incr, df.dateFrom)
When 'SS' then DateAdd(SS, #Incr, df.dateFrom)
End
From DateTable DF
Where DF.DateFrom < #DateTo
)
Insert into #ReturnVal(RetVal) Select DateFrom From DateTable option (maxrecursion 32767)
Return
End
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2020-10-01','YY',1)
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2020-10-01','DD',1)
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2016-10-31','MI',15)
-- Syntax Select * from [dbo].[udf-Create-Range-Date]('2016-10-01','2016-10-02','SS',1)
You can group by startdate or enddate. This assumes that either your startdate or enddate is the only date field relevant- not both. But you can adjust it if you have sales figures that span multiple days.
ex:
SELECT enddate,SUM(Value) FROM Sales WHERE EndDate>='2016-01-01' AND StartDate<'2016-1-03'
GROUP BY enddate