February 28, 2022 at 11:34 am
Hi
I have a very simple query as below
select Personid, StartDate, endDate
from table
where startdate >= '01-feb-21'
Example Data
223, 01-Feb-22, 04-Feb-22
354, 21,Feb-22, 22-Feb-22
I want to display it now as follows, so listing the days between the startdate and enddate for each personid
Data would be as follows
223, 01-Feb-22
223, 02-Feb-22
223, 03-Feb-22
223, 04-Feb-22
354, 21-Feb-22
354, 22-Feb-22
Any help would be appreciated
February 28, 2022 at 3:09 pm
Like this? (With thanks to Jeff Moden for the dates generator.)
DROP TABLE IF EXISTS #t1;
CREATE TABLE #t1
(
PersonId INT NOT NULL
,StartDate DATE NOT NULL
,EndDate DATE NOT NULL
);
INSERT #t1
(
PersonId
,StartDate
,EndDate
)
VALUES
(223, '20220201', '20220204')
,(354, '20220221', '20220222');
DECLARE @StartDate DATE
,@EndDate DATE
,@Days INT;
SELECT @StartDate = MIN(t.StartDate)
,@EndDate = MAX(t.EndDate)
FROM #t1 t;
SET @Days = DATEDIFF(dd, @StartDate, @EndDate);
WITH dates
AS (SELECT TOP (@Days + 1)
TheDate = DATEADD(dd, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1, @StartDate)
FROM sys.all_columns ac1
CROSS JOIN sys.all_columns ac2)
SELECT t.PersonId
,d.TheDate
FROM #t1 t
JOIN dates d
ON t.StartDate <= d.TheDate
AND t.EndDate >= d.TheDate;
February 28, 2022 at 3:19 pm
Phil is using the technique from this article: https://www.sqlservercentral.com/articles/the-numbers-or-tally-table-what-it-is-and-how-it-replaces-a-loop-1
February 28, 2022 at 3:58 pm
Install the table valued function in this script: https://www.sqlservercentral.com/scripts/a-daterange-table-valued-function
IF OBJECT_ID('[dbo].[DateRange]','IF') IS NULL BEGIN
PRINT 'CREATE FUNCTION [dbo].[DateRange]'
EXEC ('CREATE FUNCTION [dbo].[DateRange] () RETURNS TABLE AS RETURN SELECT 1 X')
END
GO
/*-- **********************************************************************
-- FUNCTION: DateRange
-- Returns a table of datetime values based on the parameters
-- Parameters:
-- @StartDate :Start date of the series
-- @EndDate :End date of the series
-- @DatePart :The time unit for @interval
-- ns : nanoseconds
-- mcs : microseconds
-- ms : milliseconds
-- ss : seconds
-- mi : minutes
-- hh : hours
-- dd : days
-- ww : weeks
-- mm : months
-- qq : quarters
-- yy : years
-- @Interval :The number of dateparts between each value returned
--
-- Sample Calls:
-- SELECT * FROM [dbo].[DateRange]('2011-01-01 12:24:35', '2011-02-01 12:24:35', 'ss', 2)
-- SELECT COUNT(*) FROM [dbo].[DateRange]('2018-01-01 00:00:00', '2018-01-25 20:31:23.646', 'ms', default)
-- SELECT * FROM [dbo].[DateRange]('2011-01-01', '2012-02-03', default, default)
-- SELECT * FROM [dbo].[DateRange]('2012-02-03', '2011-01-01', 'dd', 7)
-- SELECT DATEDIFF(ns,'2018-01-01 00:00:00.000', value),Value,* FROM [dbo].[DateRange]('2018-01-01 00:00:00.000', '2018-01-01 00:00:00.00001', 'ns', 100)
-- **********************************************************************/
ALTER FUNCTION [dbo].[DateRange]
(
@StartDate datetime2,
@EndDate datetime2,
@DatePart nvarchar(3)='dd',
@Interval int=1
)
RETURNS TABLE AS RETURN
WITH A(A) AS (SELECT 0 FROM (VALUES (0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) A(A)),
B(RowNum) AS (SELECT TOP(ABS(CASE @DatePart
WHEN 'ns' THEN DATEDIFF(ns, @EndDate, @StartDate)/@Interval
WHEN 'mcs' THEN DATEDIFF(mcs,@EndDate, @StartDate)/@Interval
WHEN 'ms' THEN DATEDIFF(ms, @EndDate, @StartDate)/@Interval
WHEN 'ss' THEN DATEDIFF(ss, @EndDate, @StartDate)/@Interval
WHEN 'mi' THEN DATEDIFF(mi, @EndDate, @StartDate)/@Interval
WHEN 'hh' THEN DATEDIFF(hh, @EndDate, @StartDate)/@Interval
WHEN 'dd' THEN DATEDIFF(dd, @EndDate, @StartDate)/@Interval
WHEN 'ww' THEN DATEDIFF(ww, @EndDate, @StartDate)/@Interval
WHEN 'mm' THEN DATEDIFF(mm, @EndDate, @StartDate)/@Interval
WHEN 'qq' THEN DATEDIFF(qq, @EndDate, @StartDate)/@Interval
WHEN 'yy' THEN DATEDIFF(yy, @EndDate, @StartDate)/@Interval
ELSE DATEDIFF(dd, IIF(@StartDate < @EndDate, @StartDate, @EndDate), IIF(@StartDate < @EndDate, @EndDate, @StartDate))/@Interval
END) + 1)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1
FROM A A, A B, A C, A D, A E, A F, A G, A H) -- A maximum of 16^8 (or 2^32) rows could be returned from this inline tally
SELECT CASE @DatePart
WHEN 'ns' THEN DATEADD(ns, T.AddAmount, @StartDate)
WHEN 'mcs' THEN DATEADD(mcs,T.AddAmount, @StartDate)
WHEN 'ms' THEN DATEADD(ms, T.AddAmount, @StartDate)
WHEN 'ss' THEN DATEADD(ss, T.AddAmount, @StartDate)
WHEN 'mi' THEN DATEADD(mi, T.AddAmount, @StartDate)
WHEN 'hh' THEN DATEADD(hh, T.AddAmount, @StartDate)
WHEN 'dd' THEN DATEADD(dd, T.AddAmount, @StartDate)
WHEN 'ww' THEN DATEADD(ww, T.AddAmount, @StartDate)
WHEN 'mm' THEN DATEADD(mm, T.AddAmount, @StartDate)
WHEN 'qq' THEN DATEADD(qq, T.AddAmount, @StartDate)
WHEN 'yy' THEN DATEADD(yy, T.AddAmount, @StartDate)
ELSE DATEADD(dd, T.AddAmount, @StartDate)
END [Value]
FROM B
CROSS APPLY(VALUES (IIF(@StartDate<@EndDate, @interval*RowNum, @interval*-RowNum))) T(AddAmount)
GO
The just call it like this:
DROP TABLE IF EXISTS #t1
CREATE TABLE #t1
(
PersonId INT NOT NULL
,StartDate DATE NOT NULL
,EndDate DATE NOT NULL
);
INSERT #t1
(
PersonId
,StartDate
,EndDate
)
VALUES
(223, '20220201', '20220204')
,(354, '20220221', '20220222');
select t.PersonId, CONVERT(date, d.Value, 6) Date
from #t1 t
cross apply dbo.DateRange(t.StartDate, t.EndDate, 'dd', 1) d
February 28, 2022 at 4:20 pm
Install the table valued function in this script: https://www.sqlservercentral.com/scripts/a-daterange-table-valued-function
I'll say it again... that's a killer general purpose function with a lot of uses. Thanks for publishing that, Jonathan.
--Jeff Moden
Change is inevitable... Change for the better is not.
February 28, 2022 at 4:23 pm
@Ohil and @steve-2... thank you both for the honorable mention.
--Jeff Moden
Change is inevitable... Change for the better is not.
February 28, 2022 at 4:55 pm
Jonathan AC Roberts wrote:Install the table valued function in this script: https://www.sqlservercentral.com/scripts/a-daterange-table-valued-function
I'll say it again... that's a killer general purpose function with a lot of uses. Thanks for publishing that, Jonathan.
Thank you Jeff
Wow, nearly at 1 million points!
February 28, 2022 at 4:57 pm
I've been called many things, but it's a first for Ohil
The "O" is apparently because "OH! More coffee, please!" 4 Letters and I phat-phingered 25% of them <headdesk>
--Jeff Moden
Change is inevitable... Change for the better is not.
Viewing 9 posts - 1 through 9 (of 9 total)
You must be logged in to reply to this topic. Login to reply
This website stores cookies on your computer.
These cookies are used to improve your website experience and provide more personalized services to you, both on this website and through other media.
To find out more about the cookies we use, see our Privacy Policy