查询大厅预订情况

uyto3xhc  于 2022-10-03  发布在  其他
关注(0)|答案(2)|浏览(157)

我正在做一个大厅预订系统,我一直在努力解决预订模块的问题

我有两张表HallsBookings

带样本数据的霍尔斯表

id   hallName   hallType  numSeats  status
---------------------------------------------
1   Hall 1      Normal    500       active
2   Hall 2      VIP       30        active
3   Hall 3      VVIP      5         active
4   Hall 4      Normal    60        active
5   Hall 5      Normal    80        active
6   Hall 4+5    Normal    140       active

样本数据预订表

id custId hallId beginDate    endDate    time        status
-----------------------------------------------------------------
1   1     1      2022-09-26   2022-09-26  morning     confirmed
2   6     4      2022-09-26   2022-09-26  evening     cancelled
3   4     3      2022-09-26   2022-09-26  full time   pending
4   9     4      2022-09-26   2022-09-30  after noon  confirmed

预约时间为“上午”、“中午”、“晚上”和“全天”。

我一直在尝试预订验证以及一份显示大厅预订情况的报告

编辑

在我编辑并删除了第二部分的评论中的建议后,如果我想不出来,可能会单独发帖

这就是我想要的结果

可以按结束日期筛选记录(例如2022-09-26)

如果存在未取消提供的BeginDate的预订,则应将该时间段标记为Booked

如果不存在所提供的BeginDate或其已取消的预订,则应将该时间段标记为Available

如果full time预订插槽指定用于提供的BeginDate,则这3个插槽应始终标记为Booked

以下是可能使事情复杂化的转折

Halls table可以看到,6号厅是4号厅和5号厅的组合,这意味着如果其中任何一个厅被预订,6号厅应该标记为unavailable,甚至Booked也可以。

总体而言,以下是基于上述预订表的示例结果

hallName   hallType  morning   after noon   evening
------------------------------------------------------
hall 1     Normal    Booked      available    available
hall 2     VIP       available   available    available
hall 3     VVIP      Booked      Booked       Booked
hall 4     Normal    available   Booked       available
hall 5     Normal    available   available    available
hall 6     Normal    available   unavailable  available

如果我们使用带有样例数据的Booking表,结果应该如下所示

我对联合、合并等我认为的解决方案并不是很熟悉。我尝试了在匹配时和不匹配时合并,但无法解决问题

然后我试着向左连接霍尔斯的table和预订的table,这似乎是到目前为止最接近的,结果很清楚。

DECLARE @date NVarchar(50) = '2022-09-26'
SELECT h.id, h.hallName, h.hallType, b.time FROM Halls h LEFT JOIN 
        Bookings b ON b.hallId=h.id WHERE b.beginDate=@date

这将仅返回带有该日期的预订大厅

如果删除WHERE子句,则所有6个大厅都将返回,但未预订的时段将作为NULL返回

顺便说一句,我正在处理最后一个模块,起初我使用的是单一签入日期和需求范围beginDate&endDate&也就是出现问题的时候。

wfveoks0

wfveoks01#

首先,您需要修改您的设计,您打算如何存储Hall 6Hall 4 + 5组合的信息

一种简单的方法是在Halls表中添加另一列来指示这一点。示例

create table Halls
(
  id int,
  hallName varchar(10),   
  hallType varchar(10),  
  numSeats int,
  status varchar(10),
  combine_id int
);

insert into Halls values
(4,   'Hall 4',      'Normal',     60,       'active', 6),
(5,   'Hall 5',      'Normal',     80,       'active', 6),
(6,   'Hall 4+5',    'Normal',    140,       'active', null);

一旦放置到位,您需要平移Bookings以处理合并的大厅。这是由CTE BookingData执行的。如果Hall 4Hall 5pendingconfirmed,它将为Hall 6创建行。同样,反过来也是如此。当Hall 6Booked时,Hall 4Hall 5将不可用。

在此之后,只需简单地旋转数据

解决方案:

DECLARE @date date = '2022-09-26';

with BookingData as
(
  select b.hallId, b.time, b.status, beginDate
  from   Bookings b

  union all

  select hallId = h.combine_id, b.time, 
         status = case when b.status in ('pending', 'confirmed')
                       then 'unavailable'
                       else 'available'
                       end, 
         beginDate
  from   Bookings b
         inner join Halls h on b.hallId = h.id
  where  h.combine_id is not null

  union all

  select hallId = h.id, b.time, 
         status = case when b.status in ('pending', 'confirmed')
                       then 'unavailable'
                       else 'available'
                       end,   
         beginDate
  from   Bookings b
       inner join Halls h on b.hallId = h.combine_id
  where  h.combine_id is not null
)
SELECT  id, 
        hallName, 
        hallType, 
        [morning]   = isnull([morning], 'available'), 
        [afternoon] = isnull([afternoon], 'available'), 
        [evening]   = isnull([evening], 'available')
FROM
(
    SELECT  h.id, h.hallName, h.hallType, t.timeSlot,
            status = case when b.status in ('pending', 'confirmed') 
                          then 'Booked' 
                          when b.status in ('cancelled')
                          then 'unavailable'
                          when b.status in ('unavailable')
                          then b.status
                          else NULL
                          end
    FROM    Halls h 
            LEFT JOIN BookingData b  ON  b.hallId     = h.id 
                                     and b.beginDate  = @date
            OUTER APPLY
            (
                select timeSlot = 'morning'   where b.time in ('morning', 'full time')
                union all
                select timeSlot = 'afternoon' where b.time in ('afternoon', 'full time')
                union all
                select timeSlot = 'evening'   where b.time in ('evening', 'full time')
            ) t
) D
PIVOT
(
    MAX (status)
    FOR timeSlot in ( [morning], [afternoon], [evening] )
) P

db<>fiddle demo

2hh7jdfx

2hh7jdfx2#

您的问题非常复杂,因为表没有正确地实现“组合大厅”的规范化。我们需要使用字符串操作分离Hall 4+5,然后将提取的信息存储在某个位置。以下是我能想到的问题:

with
 composite_halls as
  (select *,
    substring(hallName, charindex(' ', hallName) + 1,
    charindex('+', hallName) - charindex(' ', hallName) - 1) as id1,
    right(hallName, len(hallName) - charindex('+', hallName)) as id2,
    (null) as id3
  from halls where charindex('+', hallName) > 0),
 singular_halls as
  (select *,
   (select ch.id2 from composite_halls as ch where ch.id1 = h.id) as id1,
   (select ch.id1 from composite_halls as ch where ch.id2 = h.id) as id2,
   (select ch.id from composite_halls as ch where ch.id1 = h.id or ch.id2 = h.id) as id3
  from halls as h where charindex('+', hallName) = 0),
 all_halls as (
  select * from singular_halls
  union
  select * from composite_halls),
 valid_bookings as (
  select * from bookings where status = 'confirmed'
        and beginDate >= '2022-09-26' and endDate <= '2022-09-26')
select *,
  (case when exists (
          select *
          from valid_bookings as vb
          where (time = 'morning' or time = 'full time')
             and (vb.hallId = h.id
              or (vb.hallId = h.id1 and h.id3 is null)
              or (vb.hallId = h.id2 and h.id3 is null)
              or vb.hallId = h.id3))
    then 'booked'
    else 'available'
    end) as morning
  from all_halls as h

你可以在小提琴上试一下:https://dbfiddle.uk/baQyI1Y7

它看起来有点可恶,我相信其他人可以写出更短的查询。

上面的查询使用了4个CTE,其中3个处理提取相关“组合大厅”的e1d1d1。composite_halls将从hallName中提取数字,并将它们放入id1id2中。singular_halls将把对方的id放在id1id2中,将其组合放在id3中。all_halls将两个结果合并为一个。valid_bookings筛选给定时间范围的bookings,并且仅获取confirmed``bookings

下一步,它检查all_halls条目中是否有任何bookingshallId对应于idid1id2id3中的任何一个。到目前为止,它只处理morning预订,并且只提供bookedavailable状态。您可以通过添加更多case when来扩展它以提供unavailable,以专门处理id1id3。您可以通过更改case when子句中的time参数,以相同的方式处理after noonevening

我不认为上面的查询对于实时应用程序来说性能足够好。特别是我们逐行运作的事实,是从“合并”的大厅中提取相关的大厅。

我相信,如果你把table正常化一点,事情会容易得多。我觉得这就像用TSQL做EXCEL一样,这看起来不太对。

相关问题