获取重叠日期的房价

时间:2017-08-29 12:01:29

标签: sql sql-server

我在这个结构中有表:

id  accom_id    room_type_id    date_from   date_to        price_per_room   
3   1           2               2017-09-01  2017-09-10     70.00    
5   1           2               2017-09-11  2017-09-20     100.00

让我们说我想留在2017-09-07至2017-09-15。因此,对于DATEDIFF,我需要计算价格为70天的天数以及价格为100天的天数。最后我想显示总数。

任何人都可以帮我构建此查询吗?我希望它清楚什么问题!

5 个答案:

答案 0 :(得分:2)

假设没有定义重叠范围,并且假设给定的所有范围都是包容性的,我们可以使用CTE获得数据,然后是简单的聚合问题:

declare @t table (date_from date,date_to date, price_per_room int)
insert into @t (date_from,date_to,price_per_room) values
('20170901','20170910',70.00 ),
('20170911','20170920',100.00)
declare @Start date
declare @End date
select @Start = '20170907',@End = '20170915'

;With IncludedPeriods as (
    select
        CASE WHEN @Start > date_from THEN @Start ELSE date_from END as fromDT,
        CASE WHEN @End < date_to THEN @End ELSE date_to END as ToDT,
        price_per_room
    from
        @t
    where
        date_from <= @End and
        @Start <= date_to
)
select
    SUM(price_per_room * (1 + DATEDIFF(day,fromDT,ToDT)))
from
    IncludedPeriods

请注意,我们会在DATEDIFF结果中添加一个,因为它会计算过渡,但我假设来自的句点 &#39; 20170911&#39; to &#39; 20170911&#39;应该算一天和更长的时间。

与其他一些试图列举各种&#34;案例的答案不同。对于重叠,这使用简单规则 - 如果第一个在第二个结束之前开始则两个周期重叠,如果第二个结束在第一个结束之前开始则 - 这是{{1 CTE里面的子句。为了确定重叠的范围,我们采用两个开始日期的后期和两个结束日期中较早的日期 - 这是where表达式正在做什么。如果我们在日期操作时使用了标量CASEMIN函数,那么我更倾向于使用SQL Server中内置的函数。

答案 1 :(得分:0)

在SQL Server中,您可以执行以下操作:

select dateadd(d, number, '20170801')
from master.dbo.spt_values
where type='P' and (number <= datediff(d, '20170801', '20170810'))

计算总天数(在where子句中),并选择从0到总天数的数字(master.dbo.spt_values是SQL Server中的一个有用的表)。否则,您可以创建一个从0到?的递增数字的表。然后你将startdate添加到数字中。所以你得到预订的所有日子:

2017-08-01 
2017-08-02 
2017-08-03 
2017-08-04 
2017-08-05 
2017-08-06 
2017-08-07 
2017-08-08 
2017-08-09 
2017-08-10 

然后你可以在date_from和date_to上加入你给定的price_table,你可以计算你的总和。

编辑:只是为了完成它......: - )

SELECT SUM(price_per_room)
FROM master.dbo.spt_values
    LEFT OUTER JOIN room_prices AS rp ON (date_from <= DATEADD(d, number, my_start_date) AND DATEADD(d, number, my_start_date) <= date_to)
WHERE type='P' AND (number <= DATEDIFF(d, my_start_date, my_end_date))

答案 2 :(得分:-1)

您可以使用日历或日期表进行此类操作。

如果不采用创建表格的实际步骤,您可以使用日期为common table expression的特殊表格,如下所示:

<form class="container">
    <div class="form-group">
        <label class="form-control-label" for="inputSuccess1">Input with success</label>
        <input type="text" class="form-control is-valid" id="inputSuccess1">
        <div class="valid-feedback">Success! You've done it.</div>
    </div>
</form>

rextester演示:http://rextester.com/MCF52261

返回:

declare @fromdate date = '20170907';
declare @thrudate date = '20170915';
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
  select top (datediff(day, @fromdate, @thrudate)+1) 
      [Date]=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
                cross join n as tenK cross join n as hundredK
   order by [Date]
)
select total_price = sum(price_per_room)
from dates d
  inner join t
    on d.date >= t.date_from
   and d.date <= t.date_to

有关价格和日期的更详细分类,您可以将以上+-------------+ | total_price | +-------------+ | 780 | +-------------+ 换成以下内容:

select

rextester演示:http://rextester.com/NKZD1468

返回:

select 
    fromdate = min(date)
  , thrudate = max(date)
  , days = count(*)
  , price_per_room = avg(price_per_room)
  , total = sum(price_per_room)
from dates d
  inner join t
    on d.date >= t.date_from
   and d.date <= t.date_to
group by grouping sets ((price_per_room),())

<小时/> 数字和日历表参考:

答案 3 :(得分:-1)

我建议使用Date表(包含所有日期的表)或派生表来填充这些日期(您可以在线轻松找到它),如下所示:

SELECT p.id,p.room_type_id,sum(p.price_per_room)
FROM(
    SELECT t.date,s.price_per_room,s.id,s.room_type_id
    FROM (DATES QUERY \ DATE_TABLE) t
    LEFT JOIN s.yourTable
     ON(t.date between s.date_from and s.date_to)) p
WHERE p.id = YourID and p.room_type_id = YourTypeId
 AND p.date between yourStartDate and yourEndDate
GROUP BY p.id,p.room_type_id

在价格的日期范围内为每个日期填充一行,因此它会知道每天的价格是多少,然后只是在您想要的日期之间加上价格。

答案 4 :(得分:-1)

对所有四种可能情况使用UNION ALL也可以完成这项工作

SELECT SUM(x.p)
FROM
(
    SELECT (DATEDIFF(DAY, @from, date_to)+1)* price p
    FROM tab
    WHERE date_to BETWEEN @from AND @to AND NOT date_from BETWEEN @from AND @to
      UNION ALL
    SELECT ISNULL(SUM((DATEDIFF(DAY, date_from, date_to)+1)* price), 0) p
    FROM tab
    WHERE date_to BETWEEN @from AND @to AND date_from BETWEEN @from AND @to
      UNION ALL
    SELECT (DATEDIFF(DAY, date_from, @to)+1)* price p
    FROM tab
    WHERE date_from BETWEEN @from AND @to AND NOT date_to BETWEEN @from AND @to
      UNION ALL
    -- in the case that the (@from, @to) interval is completely in one row interval
    SELECT (DATEDIFF(DAY, @from, @to)+1)* price p
    FROM tab
    WHERE date_from <= @from AND date_to >= @to      
)x;

sqlfiddle demo