【问题标题】:Calculating the peak capacity of hotels with Sql用Sql计算酒店的峰值容量
【发布时间】:2012-11-17 22:31:18
【问题描述】:

有许多酒店的床位容量不同。我需要了解在任何一天,每家酒店占用了多少张床位。

样本数据:

 HOTEL      CHECK-IN     CHECK-OUT
   A       29.05.2010   30.05.2010
   A       28.05.2010   30.05.2010
   A       27.05.2010   29.05.2010
   B       18.08.2010   19.08.2010
   B       16.08.2010   20.08.2010
   B       15.08.2010   17.08.2010

中间结果:

HOTEL      DAY          OCCUPIED_BEDS
  A     27.05.2010           1      
  A     28.05.2010           2
  A     29.05.2010           3
  A     30.05.2010           2
  B     15.08.2010           1
  B     16.08.2010           2
  B     17.08.2010           2
  B     18.08.2010           2
  B     19.08.2010           2
  B     20.08.2010           1

最终结果:

 HOTEL     MAX_OCCUPATION  
   A            3
   B            2

A similar question is asked before. 我想获取两个日期之间的日期列表 (as Tom Kyte shows) 并使用 group by 计算每天的容量。问题是我的桌子比较大,我想知道是否有更便宜的方法来完成这项任务。

【问题讨论】:

标签: sql oracle oracle11gr2


【解决方案1】:

我认为没有比您在问题中概述的方法更好的方法了。创建您的天数表(或即时生成一个)。我个人喜欢放一个,每年更新一次。

了解分析函数的人可能无需内部/外部查询就可以做到这一点,但由于内部分组是外部分组的子集,因此没有太大区别。

Select
  i.Hotel,
  Max(i.OccupiedBeds)
From (
  Select
    s.Hotel,
    d.DayID,
    Count(*) As OccupiedBeds
  From
    SampleData s
      Inner Join
    Days d
      -- might not need to +1 depending on business rules.
      -- I wouldn't count occupancy on the day I check out, if so get rid of it
      On d.DayID >= s.CheckIn And d.DayID < s.CheckOut + 1 
  Group By
    s.Hotel, 
    d.DayID
  ) i
Group By
  i.Hotel

玩了一会儿后,如果没有内部查询,我无法获得分析函数版本:

如果速度确实是一个问题,您可以考虑在主表上维护一个带有触发器的中间表。

http://sqlfiddle.com/#!4/e58e7/24

【讨论】:

  • 这是一个OLAP环境。你知道一个实用的方法来创建一个跨越 6 年的天表,即 01.01.2008-01.12.2013
【解决方案2】:

创建一个包含您感兴趣的日期的临时表

create table #dates (dat datetime)
insert into #dates (dat) values ('20121116')
insert into #dates (dat) values ('20121115')
insert into #dates (dat) values ('20121114')
insert into #dates (dat) values ('20121113')

通过加入带有日期的预订来获得中间结果,以便每个预订日“生成”一个

SELECT Hotel, d.dat, COUNT(*) from bookings b
INNER JOIN #dates d on d.dat BETWEEN b.checkin AND b.checkout
GROUP BY Hotel, d.dat 

终于得到了最大值

SELECT Hotel, Max(OCCUPIED_BEDS) FROM IntermediateResult GROUP BY Hotel

【讨论】:

  • 海报没有“中间结果”。他有“样本数据”
  • 哦,是的 - 这就是挑战。我明白了。
【解决方案3】:

性能问题在于连接条件不是基于相等性,这使得哈希连接成为不可能。假设我们有一张hotel_day 表,里面有酒店天对,我会尝试这样的事情:

select ch_in.hotel, ch_in.day,
       (check_in_cnt - check_out_cnt) as occupancy_change
from   ( select d.hotel, d.day, count(s.hotel) as check_in_cnt
         from   hotel_days d,
                sample_data s
         where  s.hotel(+) = d.hotel
           and  s.check_in(+) = d.day
         group  by d.hotel, d.day
       ) ch_in,
       ( select d.hotel, d.day, count(s.hotel) as check_out_cnt
         from   hotel_days d,
                sample_data s
         where  s.hotel(+) = d.hotel
           and  s.check_out(+) = d.day
         group  by d.hotel, d.day
       ) ch_out
where  ch_out.hotel = ch_in.hotel
  and  ch_out.day = ch_in.day

权衡是双重全扫描,但我认为它仍然会运行得更快,并且可以并行化。 (我假设 sample_data 很大,主要是由于预订数量,而不是酒店本身的数量。)输出是特定日期特定酒店的入住率变化,但这可以很容易地总结为总值,无论是分析函数或(可能更有效)带有批量收集的 PL/SQL 过程。

【讨论】:

    猜你喜欢
    • 2022-11-11
    • 2021-11-10
    • 2016-01-28
    • 1970-01-01
    • 2022-11-02
    • 2017-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多