If you want to select date ranges based on quarters, you could use a calendar table to facilitate that. The following example uses snippets from Creating a date dimension or calendar table in SQL Server - Aaron Bertrand.
-- if regional settings are interfering with interpretation of dates/literals:
/*
set datefirst 7;
set dateformat mdy;
set language us_english;
--*/
if object_id('dbo.Calendar_Example') is not null drop table dbo.Calendar_Example;
create table dbo.Calendar_Example (
[Date] date not null
, [Year] smallint not null
, [Day] tinyint not null
, [Month] tinyint not null
, [Quarter] tinyint not null
, [YearQuarter] char(7) not null /* yyyy-qq */
, constraint pk_Calendar_Quarters primary key clustered (date)
);
declare @FromDate date = '20160101';
declare @ThruDate date = '20201231';
with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, d as (
select DateValue=convert(date,dateadd(day
, row_number() over (order by (select 1)) -1, @fromdate))
from n as deka
cross join n as hecto
cross join n as kilo /* 2.73 years */
cross join n as [10k] /* 27.3 years */
--cross join n as [100k] /* 273 years */
--cross join n as mega
)
insert into dbo.Calendar_Example
([Date], [Year], [Day], [Month], [Quarter], [YearQuarter])
select top (datediff(day, @FromDate, @ThruDate)+1)
[Date] = DateValue
, [Year] = convert(smallint,datepart(year,DateValue))
, [Day] = convert(tinyint,datepart(day,DateValue))
, [Month] = convert(tinyint,datepart(month,DateValue))
, [Quarter] = convert(tinyint,datepart(quarter,DateValue))
, [YearQuarter] = convert(char(7) ,convert(char(4), datepart(year,DateValue))
+'-Q'+convert(char(1), datepart(quarter,DateValue)))
from d
order by DateValue;
calendar and numbers tables reference:
From there, you could use a table valued parameter (TVP) to pass a set of quarters to include in the select. Example:
create type dbo.YearQuarter_udt as table (
YearQuarter char(7) not null
, primary key (YearQuarter)
);
go
create procedure dbo.Select_Using_YearQuarter_udt (
@YearQuarter dbo.YearQuarter_udt readonly
) as
begin;
set nocount on;
set xact_abort on;
with c as (
select ce.[Date]
from dbo.Calendar_Example ce
inner join @YearQuarter yq on yq.YearQuarter = ce.YearQuarter
)
select *
from MM
inner join c on mm.CDate = c.Date;
end;
go
If you want to pass a series of date ranges, you could do something like this:
create type dbo.DateRange_udt as table (
FromDate date not null
, ThruDate date not null
primary key (FromDate,ThruDate)
);
go
create procedure dbo.Select_Using_DateRange_udt (
@DateRange dbo.DateRange_udt readonly
) as
begin;
set nocount on;
set xact_abort on;
select *
from MM
inner join @DateRange dr on mm.CDate >= dr.FromDate
and mm.CDate <= dr.ThruDate
end;
go
table valued parameter reference:
An alternative to TVPs, you can split the @innerstring variable.
create procedure dbo.Select_Using_YearQuarter_Delimited (
@DelimitedString nvarchar(256)
) as
begin;
set nocount on;
set xact_abort on;
with c as (
select ce.[Date]
from dbo.Calendar_Example ce
inner join dbo.DelimitedSplitN4k(@DelimitedString,';') as d
on convert(char(7),d.Item) = ce.YearQuarter
)
select *
from MM
inner join c on mm.CDate = c.Date;
end;
go
The above example assumes a delimiter of ';', and uses Jeff Moden's DelimitedSplitN4k (comments removed, slightly reformatted).
create function dbo.DelimitedSplitN4K (
@pString nvarchar(4000)
, @pDelimiter nchar(1)
)
returns table with schemabinding as
return
with e1(n) as (
select 1 union all select 1 union all select 1 union all
select 1 union all select 1 union all select 1 union all
select 1 union all select 1 union all select 1 union all select 1
)
, e2(n) as (select 1 from e1 a, e1 b)
, e4(n) as (select 1 from e2 a, e2 b)
, cteTally(n) as (select top (isnull(datalength(@pString)/2,0))
row_number() over (order by (select null)) from e4)
, cteStart(n1) as (select 1 union all
select t.n+1 from cteTally t where substring(@pString,t.n,1) = @pDelimiter)
, cteLen(n1,l1) as(select s.n1
, isnull(nullif(charindex(@pDelimiter,@pString,s.n1),0)-s.n1,4000)
from cteStart s
)
select ItemNumber = row_number() over(order by l.n1)
, Item = substring(@pString, l.n1, l.l1)
from cteLen l;
go
splitting strings reference: