2011-12-13 77 views
-3

我有一个SQL表看起来像这样总结价格在SQL日期范围

PricelistID periodID periodstart  periodend   price 
1   1   2011/05/01   2011/05/31  50 
1   2   2011/06/01   2011/06/30  70 
1   3   2011/07/15   2011/07/31  80 
2   4   2011/05/01   2011/05/31  100 
2   5   2011/06/01   2011/06/30  110 
2   6   2011/07/01   2011/07/31  120 

如上所示,我已经定义了一段内的每一天时段和每日价格对应(periodstart包括,periodend包括) 。

现在我想找到一个总价一段2011/05/20(含) - 2011年5月27日(不含)

两个语句必须满足

a)如果在periodend之间有差距!和periodstart!对于2011/05/20 - 2011/05/27的搜索期限,不应返回任何结果。或每天一个时期内2011/05/20陈述不同 - 2011年5月27日应该是内部的一个或多个日期范围periodstart - 在SQL表

b)否循环

结果集应定义peroidend看起来像

PricelistID total 

    1    350 
    2    700 

感谢

回答

1

这是一个可行的解决方案。

你只需要创建一个递归CTE的日期和你家...

declare @startDate date = '2011-05-20' 
     ,@endDate date = '2011-05-27' 

;with testData(PricelistID,periodID,periodstart,periodend,price) 
as 
(
select 1, 1, cast('2011/05/01' as date), cast('2011/05/31' as date), 50 
union all 
select 1, 2, cast('2011/06/01' as date), cast('2011/06/30' as date), 70 
union all 
select 1, 3, cast('2011/07/15' as date), cast('2011/07/31' as date), 80 
union all 
select 2, 4, cast('2011/05/01' as date), cast('2011/05/31' as date), 100 
union all 
select 2, 5, cast('2011/06/01' as date), cast('2011/06/30' as date), 110 
union all 
select 2, 6, cast('2011/07/01' as date), cast('2011/07/31' as date), 120 
) 
,dates(d) 
as 
(
select @startDate 
union all 
select dateadd(day, 1, d) 
from dates 
where d < dateadd(day, -1, @endDate) 
) 
select td.pricelistid 
     ,sum(td.price) as total 
from testData td 
join dates 
    on dates.d >= td.periodstart 
    and dates.d <= td.periodend 
group by 
    td.pricelistid 
+0

好看与CTE,但是这个代码不用日期差距解决问题。尝试'2011/06/25' - '2011/07/05'。它不应该返回数据,因为有一段时间缺少2011-07-01 - 2011-07-14。 – mko

+0

哦,我没有注意到差距。不过,我想这可以通过比较来自CTE的COUNT(*)和来自select的COUNT(*)来解决。并把它放在'SUM'的'CASE'语句中。 – Johan

1

只有一个循环:

-- tables 
create table #prices (
PricelistID int, 
periodID int, 
periodstart  datetime, 
periodend   datetime, 
price int) 


create table #interval_price (
PricelistID int, 
price int, 
period datetime 
) 

create table #test_gaps (
PricelistID int, 
times int 
) 


-- inserts 
insert into #prices values (1,1,convert(datetime, '2011/05/01', 111), convert(datetime, '2011/05/31', 111),50) 
insert into #prices values (1,2,convert(datetime, '2011/06/01', 111), convert(datetime, '2011/06/30', 111),70) 
insert into #prices values (1,3,convert(datetime, '2011/07/15', 111), convert(datetime, '2011/07/31', 111),80) 
insert into #prices values (2,4,convert(datetime, '2011/05/01', 111), convert(datetime, '2011/05/31', 111),100) 
insert into #prices values (2,5,convert(datetime, '2011/06/01', 111), convert(datetime, '2011/06/30', 111),110) 
insert into #prices values (2,6,convert(datetime, '2011/07/01', 111), convert(datetime, '2011/07/31', 111),120) 


-- variables 
declare @periodStart datetime, @periodEnd datetime 
select @periodStart = convert(datetime, '20110520', 112) 
select @periodEnd = convert(datetime, '20110527', 112) 



declare @period datetime 
select @period = @periodStart 

declare @price int, @PriceListID int 



while (@period < @periodEnd) 
begin 
    select @price = NULL, @PriceListID = NULL 

    insert into #interval_price select PricelistID, price, @period from #prices where @period >= periodstart and @period < periodend 

    select @period = dateadd(dd, 1, @period) 
end 

insert into #test_gaps select PriceListID, count(price) from #interval_price group by PricelistID 



if (select count(distinct times) from #test_gaps) = 1 
begin 
    if (select distinct times from #test_gaps) = (select datediff(dd,@periodStart , @periodEnd)) 
    begin 
     select PriceListID, sum(price) [total] from #interval_price group by PricelistID 
    end 
end 

drop table #prices 
drop table #interval_price 
+0

谢谢,但我认为循环会大幅度降低大量时段的表现。 – mko

+1

@John测试一下吧!我已经添加了你所引用的test_gaps部分。 –