我目前正在使用Sql Server语言编写C#,尝试设计一个查询,我必须选择四分之一(Q1,Q2,Q3,Q4)。
我的问题是,假设前端的用户只选择了Q1,那么我可以将查询设置为Q1季度的日期范围,如果用户选择Q1,那么我仍然可以设置日期范围对于Q1和Q2,因为它们属于序列日期范围。
但是如果用户选择Q1和Q3,那么我如何准备日期范围查询(在存储过程或简单选择查询中)并为此执行。
我正在尝试这个但没有用。
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
@innerstring我想作为参数发送到sql存储过程,然后准备/执行它。 但我不想使用临时表来存储日期范围的查询数据,然后将结果联合起来。因为我也有不同的参数。
感谢。
答案 0 :(得分:3)
您不需要in
。这应该有效:
where (cdate between '2015-05-20' and '2015-06-01' or
cdate between '2016-06-03' and '2016-06-04'
)
请注意,带有日期的between
可能是危险/中等的,正如Aaron Bertrand在一篇有趣的blog中所解释的那样。我会去:
where (cdate >= '2015-05-20' and cdate < '2015-06-02' or
cdate >= '2016-06-03' and cdate < '2016-06-05'
)
即使cdate
有时间成分,这也能正常运行。
答案 1 :(得分:0)
如果要根据季度选择日期范围,可以使用日历表来实现这一点。以下示例使用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;
日历和数字表参考:
从那里,您可以使用表格值参数(TVP)来传递一组季度以包含在选择中。例如:
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
如果您想传递一系列日期范围,可以执行以下操作:
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
表值参数参考:
替代TVP,您可以拆分 @innerstring
变量。
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
以上示例假定分隔符为“;”,并使用Jeff Moden's DelimitedSplitN4k(删除了注释,稍微重新格式化)。
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
拆分字符串参考: