2

I am currently working on C# with Sql Server Language, trying to design a query where I have to select quarters(Q1, Q2, Q3, Q4).

My issue is that, suppose if the user from the front end selects only Q1 then I can set the query to date range for quarter Q1, and if the user selects Q1 and as well Q2 then I can still set the date range for Q1 and Q2 because they fall under sequence date ranges.

But if the user selects Q1 and Q3 then how do I prepare date range query(either in stored procedure or simple select query) and excecute for this.

I was trying with this but no use.

where CDate in(cdate between '2015-05-20' and '2015-06-01' 
  and CDate between '2016-06-03' and '2016-06-04'

select * from MM  where @innerstring

The @innerstring I want to send as a parameter to the sql stored procedure and then prepare/execute it. but I don't want to use temp table to store query data for saperate date ranges and then union that result. because I have different parameters with me as well.

Thanks.

2
  • Why the MySQL tag? Commented Jan 2, 2017 at 13:09
  • You have to add example data and expected result, we do not fully understand what you would like to do with quaters or dates. Commented Jan 2, 2017 at 19:30

2 Answers 2

7

You don't need the in. This should work:

where (cdate between '2015-05-20' and '2015-06-01' or
       cdate between '2016-06-03' and '2016-06-04'
      )

Note that between with dates can be dangerous/midleading, as Aaron Bertrand explains in an interesting blog. I would go for:

where (cdate >= '2015-05-20' and cdate < '2015-06-02' or
       cdate >= '2016-06-03' and cdate < '2016-06-05'
      )

This safely works even when cdate has a time component.

Sign up to request clarification or add additional context in comments.

6 Comments

Nop its just selecting the records for the first date range after or its doing nothing. I want to include the result for both the date ranges, I mean select all records from cdate >= '2015-05-20' and cdate < '2015-06-02' and then include the result from cdate >= '2016-06-03' and cdate < '2016-06-05' aswell.
Yes thanks. I worked now. but how do I prepare it in SQL Query, I am selecting the Q1 through Q4 randomly, so how do I prepare the query based on my situation. The query has to be in sql stored procedure.
Gordon Linoff, Any idea about above.
I would add some parenthesis for better readability: where ((cdate >= '2015-05-20' and cdate < '2015-06-02') or (cdate >= '2016-06-03' and cdate < '2016-06-05') )
How do I make the entire where clause in stored procedure to replace with string value. like above I just edited.
|
0

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:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.