【问题标题】:Summarizing prices in sql date ranges [closed]总结sql日期范围内的价格[关闭]
【发布时间】:2012-01-19 08:55:01
【问题描述】:

我有一个看起来像这样的 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/05/27(不包括)期间的总价

必须满足两个陈述

a) 如果 periodend 之间有间隔!!和周期开始!!对于搜索周期 2011/05/20 - 2011/05/27,不应返回任何结果。或者在 2011/05/20 - 2011/05/27 期间内的每一天都有不同的表述,应该在一个或多个日期范围内 periodstart - peroidend 在 sql 表中定义

b) 没有循环

结果集应该是这样的

PricelistID   total

    1             350
    2             700

谢谢

【问题讨论】:

    标签: tsql date common-table-expression date-range


    【解决方案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
    

    【讨论】:

    • 用 cte 看起来不错,但是这段代码不能解决日期间隔的问题。尝试“2011/06/25”-“2011/07/05”。它不应该返回数据,因为缺少 2011-07-01 - 2011-07-14 的期间。
    • 哦,我没注意到差距。但是,我想可以通过将 CTE 中的 COUNT(*) 与 select 中的 COUNT(*) 进行比较来解决。并将其放在CASE-statement 中,围绕SUM
    【解决方案2】:

    只有一个循环:

    -- 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
    

    【讨论】:

    • 谢谢,但我认为循环会大大降低大量周期的性能。
    • @John 测试一下!我已经添加了你提到的 test_gaps 部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多