IF EXISTS(SELECT name FROM sys.procedures WHERE name='cal_list')
DROP PROC cal_list
GO
CREATE PROC cal_list (
@dt date = NULL, -- Start Date. Today if a value is not passed.
@include_dt char(1) = 'Y', -- Y Include @dt in the return set, N do not include
@previous_or_next char(1) = 'P', -- P Previous .. before @dt, N next .. after @dt
@row_count int = 100) AS
/*
2015-09-016 Jim Horn, Original. http://www.jimhorn.biz All copies of this code must include this line.
*/
-- TESTING ONLY, comment out the below line in production
-- Declare @dt date = '20150905', @include_dt char(1) = 'Y', @previous_or_next char(1) = 'P', @row_count int = 12
-- If date was passed as NULL, use today
SET @dt = CASE WHEN @dt IS NULL THEN CAST(GETDATE() as date) ELSE @dt END
;WITH days_rows AS (
SELECT TOP(@row_count + 1) PKDate
FROM days
WHERE
(@previous_or_next = 'P' AND PKDate <= @dt) OR
(@previous_or_next = 'N' AND PKDate >= @dt)
ORDER BY
CASE @previous_or_next WHEN 'P' THEN PKDate END DESC,
CASE @previous_or_next WHEN 'N' THEN PKDate END),
days_ranked AS (
SELECT PKDate, RANK() OVER (ORDER BY PKDate) as row_number
FROM days_rows),
days_ranked_max AS (SELECT MAX(row_number) as row_number_max FROM days_ranked)
SELECT PKDate
FROM days_ranked dr
WHERE (
(@previous_or_next = 'P' AND @include_dt = 'Y' AND row_number >= (SELECT row_number_max FROM days_ranked_max) - @row_count + 1) OR
(@previous_or_next = 'P' AND @include_dt = 'N' AND row_number <> (SELECT row_number_max FROM days_ranked_max) AND row_number >= (SELECT row_number_max FROM days_ranked_max) - @row_count) OR
(@previous_or_next = 'N' AND @include_dt = 'Y' AND row_number <= @row_count) OR
(@previous_or_next = 'N' AND @include_dt = 'N' AND row_number <> 1 AND row_number <= (@row_count + 1))
)
ORDER BY
CASE @previous_or_next WHEN 'P' THEN PKDate END DESC,
CASE @previous_or_next WHEN 'N' THEN PKDate END
GO
The results...
IF EXISTS(SELECT name FROM sys.objects WHERE name='fn_cal_list')
DROP FUNCTION fn_cal_list
GO
CREATE FUNCTION fn_cal_list(
@dt date = NULL, -- Start Date. Today if a value is not passed.
@include_dt char(1) = 'Y', -- Y Include @dt in the return set, N do not include
@previous_or_next char(1) = 'P', -- P Previous .. before @dt, N next .. after @dt
@row_count int = 100)
RETURNS @ret TABLE (PKDate date)
AS
BEGIN
/*
2015-09-05 Jim Horn, Original. http://www.jimhorn.biz All copies of this code must include this line.
*/
-- TESTING ONLY, comment out the below line in production
-- Declare @dt date = '20150905', @include_dt char(1) = 'Y', @previous_or_next char(1) = 'P', @row_count int = 12
-- If date was passed as NULL, use today
SET @dt = CASE WHEN @dt IS NULL THEN CAST(GETDATE() as date) ELSE @dt END
;WITH days_rows AS (
SELECT TOP(@row_count + 1) PKDate
FROM days
WHERE
(@previous_or_next = 'P' AND PKDate <= @dt) OR
(@previous_or_next = 'N' AND PKDate >= @dt)
ORDER BY
CASE @previous_or_next WHEN 'P' THEN PKDate END DESC,
CASE @previous_or_next WHEN 'N' THEN PKDate END),
days_ranked AS (
SELECT PKDate, RANK() OVER (ORDER BY PKDate) as row_number
FROM days_rows),
days_ranked_max AS (SELECT MAX(row_number) as row_number_max FROM days_ranked)
INSERT INTO @ret (PKDate)
SELECT PKDate
FROM days_ranked dr
WHERE (
(@previous_or_next = 'P' AND @include_dt = 'Y' AND row_number >= (SELECT row_number_max FROM days_ranked_max) - @row_count + 1) OR
(@previous_or_next = 'P' AND @include_dt = 'N' AND row_number <> (SELECT row_number_max FROM days_ranked_max) AND row_number >= (SELECT row_number_max FROM days_ranked_max) - @row_count) OR
(@previous_or_next = 'N' AND @include_dt = 'Y' AND row_number <= @row_count) OR
(@previous_or_next = 'N' AND @include_dt = 'N' AND row_number <> 1 AND row_number <= (@row_count + 1))
)
ORDER BY
CASE @previous_or_next WHEN 'P' THEN PKDate END DESC,
CASE @previous_or_next WHEN 'N' THEN PKDate END
RETURN
END
IF EXISTS(SELECT name FROM sys.procedures WHERE name='cal_boundaries')
DROP PROC cal_boundaries
GO
CREATE PROC cal_boundaries (@dt date, @interval char(1) = 'M', @offset int = 0) AS
/*
Get the day boundaries of a given week that contains @dt, plus or minus @offset weeks.
2015-09-05 Jim Horn, Original. http://www.jimhorn.biz All copies of this code must include this line.
*/
-- TESTING ONLY, comment out the below line in production
-- Declare @dt date = '20150905', @interval char(1) = 'M', @offset int = 0
SELECT MIN(PKDate) as dtBegin, MAX(PKDate) as dtEnd
FROM days
WHERE
(@interval = 'Y' AND continuous_year = (SELECT continuous_year FROM days WHERE PKDate = DATEADD(year, @offset, @dt))) OR
(@interval = 'Q' AND continuous_quarter = (SELECT continuous_quarter FROM days WHERE PKDate = DATEADD(quarter, @offset, @dt))) OR
(@interval = 'M' AND continuous_month = (SELECT continuous_month FROM days WHERE PKDate = DATEADD(month, @offset, @dt))) OR
(@interval = 'W' AND continuous_week = (SELECT continuous_week FROM days WHERE PKDate = DATEADD(week, @offset, @dt)))
GO
The results..
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (9)
Commented:
I have gone (quickly) through your part 1 and 2, and the thing I would have really like is to have the cal_list SP offered as a UDF instead. We often need that kind of results as part of a resultset based on another field of the query.
Author
Commented:Also let me know if I rewrite this as a function, if you think it's even worth it also showing as an SP
(air code)
Open in new window
Commented:
Commented:
Regards,
Yashwant Vishwakarma
Commented:
Mike
View More