1

我有一个简单的数据库,我想创建一个预订和调度系统。为了达到我的目标,它是开放的,所以如果需要的话,不用担心改变设计。

以下是 ERD:

在此处输入图像描述

问题如下: 我有成员可以在特定时间(预订期)预订特定地点(可预订区域) 当前的关系集允许许多成员在许多地方多次预订,并且这些可能重叠。即它允许双重预订或人们同时预订两个地方(即一次在两个地方)。

我的问题是,如何修改此数据库的设计以严格允许以下情况:会员只能预订一个地方,但可以多次预订(即 9-9:30、9:30-10、10-10:30等)。有效地允许会员预订一个地点和时间。一经预订,其他会员不得预订同一地点和时间。他们可以预订同一个地方但在不同的时间,或者在同一时间但不同的地方但不能同时预订。

我需要改变什么才能做到这一点。我宁愿只在关系中这样做,因为这很明显,但是,作为最后的手段,如果没有办法使用关系来做到这一点,我会求助于触发器,但我不想使用它们,因为它们不是和 erd 一样明显。

提前感谢您的帮助。

编辑 1:触发器和检查约束确实可以作为答案,我绝不会说这不是规范或不正确。如果这是我能做到的唯一方法,那么我将不得不这样做。但是,我之所以这样问,是因为我希望让其他程序员尽可能清楚地看到这种情况,所以这就是为什么我正在寻找一种通过关系来实现它的方法。但是,我确实接受这可能是不可能的。我只是不确定,所以这个问题。

编辑 2:我知道我说过我想在不使用约束或触发器的情况下这样做,但似乎如果不采取会使事情过于复杂的极端措施,就不可能做到这一点。但是,我确实喜欢过于复杂的答案,因为它显示了一些关于关系的真正好的想法。感谢大家。

4

3 回答 3

1

原始回复

如果我理解正确,以下场景显示了允许和不允许的示例。

Member            Book Time              Book Place
-----------------------------------------------------
John              0900-1000              Room 1
John              1000-1100              Room 1
John              1100-1200              Room 1
John              0900-1000              Room 2        <--- not allowed, member double booked
Jane              0900-1000              Room 1        <--- not allowed, room double booked

所以,你想要强制的是两个不同组的唯一性。一组是会员和预订时间,另一组是预订时间和预订地点。

您可以在这些列上创建两个唯一键,Bookings以强制任何组都不能重复。也就是说,具有重复 Book Time 的 Member 不能重复,因为它会违反唯一约束,并且具有重复 Book Places 的 Book Time 不能重复,原因相同。

编辑:我看到你在这种情况下完全反对约束,所以我的回答可能毫无意义。

EDIT2:我的解决方案假设您建立一个代理键作为Bookings表的主键。很抱歉没有提到这一点。

替代选项

这是我想到的一个古怪的想法。您可以维护 6 个表。

Member
BookTime
BookPlace
Member_BookTime
BookPlace_BookTime
Member_BookTime_BookTime_BookPlace

好吧,在你注销我之前,听我说完!您的图表有 4/6 的这些表。我提议拆分成员、BookTimes 和 BookPlaces 之间的关系。

下面有一个代理主键和一个复合唯一键,以保证一次没有成员被重复预订。

Member_BookTime
---------------
ID (PK)
Member_ID (CUK)
BookTime_ID (CUK)

并且下面有一个代理主键和一个复合唯一键,以保证一次没有房间被重复预订。

BookPlace_BookTime_ID
------------------
ID (PK)
BookPlace_ID (CUK)
BookTime_ID (CUK)

并且下面有一个复合主键和成员的预订时间和房间的预订时间之间的关系,以最终将成员与特定时间的房间联系起来。

Member_BookTime_BookTime_BookPlace
----------------------------------
Member_BookTime_ID (CPK)
BookPlace_BookTime_ID (CPK)

这有什么意义吗?在上述模式中,会员不能重复预订,房间不能重复预订。我意识到这可能是“过度规范化”,但它使关系更加清晰。

建议的约束并不是真正“隐藏”的,因为它们显示在用于定义表的 SQL 中。我了解您希望从 ERD 中显示有关数据约束的所有内容,但有时约束过于复杂。

于 2012-07-30T17:15:25.143 回答
1

如果您只想支持 30 或 15 分钟的间隔,我们可以执行以下操作。

周期表如下所示:

   ID     StartPeriod End Period
   1      0:00        0:15
   2      0:15        0:30 
   3      0:30        0:45 
   4      0:45        1:00 
   5      1:00        1:15

*等等

因此,如果您希望会员 1 在 2012 年 7 月 30 日午夜至凌晨 12:30 预订区域 1,预订描述为“睡眠”,记录将如下所示

    BookingInfo
    Id    Description
    1     "Sleep"

    Bookings
    Id     MemberId PeriodID BookingInfoId BookableAreaId Day
    1      1        1        1             1              7/30/2012
    2      1        2        1             1              7/30/2012

然后,您可以在 Bookings 上放置两个唯一索引,其中一个为 MemberId,Day,PeriodId(这将防止它们被安排在同一天的同一时间)

一个用于 BookableAreaId、Day、PeriodId(这将防止某人在同一天以相同的 15 分钟间隔重复预订同一区域)

您还可以删除 Id 字段作为 Bookings 表上的主键,并将其中一个唯一索引替换为这些字段上的主键。

抱歉格式模糊,我是这个网站的新手。由于我无法发布图片,因此将 ERD 作为链接附加(直到我获得足够的代表)

ERD

于 2012-07-30T17:32:34.253 回答
1

我会像这样更改您的数据模型:

BookingPeriods 将包含一个时间段列表。例如。您可以在早上和下午预订,这将使 StartTime 上午 9 点和 EndTime 下午 1 点。或者以一个小时为单位,这意味着记录上午 9 点到 10 点、上午 10 点到 11 点等。

Create table BookingPeriods (
    id int primary key
  , StartTime Time
  , EndTime Time
  , Description varchar(max)
)

BookingAvailability 将是时间段和日期之间的简单映射。所以你有一个每个日期的列表,其中可能有哪些时间段

Create table BookingAvailability(
    id int primary key
  , Day Date
  , PeriodId int references BookingPeriods(id)
    constraint uq_bookingAvailability unique (Day, PeriodId)
)

BookableAreas 只是成为物理位置的列表。

Create table BookableAreas(
    id int primary key
  , Name varchar(100)
  , ActivityTypeId int
  , Description varchar(max)
)

成员保持不变

Create table Members(
    id int primary key
  , FirstName varchar(100)
  , ...
 )

然后预订就变成了所有东西都汇集在一起​​的桌子。您每个可用性记录和区域的唯一记录。memberid 只是记录的一些辅助信息。

Create table Bookings(
    id int primary key
  , AvailabilityId int references BookingAvailability(id)
  , AreaId int references BookableAreas(id)
  , MemberId int references Members(id)
    constraint uq_Bookings unique (AvailabilityId, AreaId)
)

该数据模型将按如下方式使用:

确保永远不要在此处的时隙中注册“重叠”。例如,如果您想要更细粒度的细节,您需要每小时创建一条记录。

INSERT INTO BookingPeriods (id, StartTime, EndTime, Description)
VALUES (1, '9:00 AM', '12:00 AM', 'Morning'), 
       (2, '1:00 PM', '4:00 PM', 'Afternoon')

这是您可以预订的可能时间段列表。(例如周末的日期不包括在内)

INSERT INTO BookingAvailability(id, [Day], PeriodId)
VALUES (1, '20120801', 1),
       (2, '20120801', 2),
       (3, '20120801', 1),
       (4, '20120801', 2),
       (5, '20120801', 1),
       (6, '20120801', 2)

INSERT INTO BookableAreas (id, Name, ActivityTypeId, Description)
VALUES (1, 'Ground Floor', 1, 'The ground floor room'),
       (2, 'East Wing Room', 1, 'The east wing room on the first floor'),
       (3, 'West Wing Room', 1, 'The west wing room on the first floor')

INSERT INTO Members(id, FirstName)
VALUES (1, 'Barak'),
       (2, 'Tony'),
       (3, 'George')

在这里,我们尝试创建实际的预订。

INSERT INTO Bookings(id, AvailabilityId, AreaId, MemberId)
VALUES (1, 3, 1, 1) -- Barak books the ground floor on 20120801 in the morning

INSERT INTO Bookings(id, AvailabilityId, AreaId, MemberId)
VALUES (2, 3, 1, 2)  -- Tony books the ground floor on 20120801 in the morning --> error

INSERT INTO Bookings(id, AvailabilityId, AreaId, MemberId)
VALUES (2, 4, 1, 2)  -- Tony books the ground floor on 20120801 in the afternoon --> ok
于 2012-07-30T17:37:10.387 回答