数据库关系有很多很多3路混淆

时间:2012-07-30 16:43:48

标签: sql sql-server database sql-server-2008 relational-database

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

以下是ERD:

enter image description here

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

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

为了实现这一目标,我需要做些什么改变。我更喜欢在关系中这样做,因为这显然是明显的,但是,作为最后的手段,如果没有办法使用关系,我会转向触发器,但我不想使用它们,因为它们不是和erd一样明显。

提前感谢您的帮助。

编辑1:触发和检查约束确实可以作为答案,我不以任何方式说这不是常态或不正确。如果这是我能做到的唯一方法那么我就必须这样做。但是,我在问,因为我更愿意尽可能地让其他程序员明白这一点,所以这就是为什么我正在寻找通过关系来实现它的方法。但是,我确实接受这可能是不可能的。我当然不知道这个问题。

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

3 个答案:

答案 0 :(得分: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上创建两个唯一键,以强制这两个组都不能复制。也就是说,具有重复预订时间的会员不能重复,因为它会违反唯一约束,并且出于相同原因,重复预订位置的预订时间不能重复。

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

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)

这有什么意义吗?在上述架构中,会员不能被双重预订,且房间不能被双重预订。我意识到它可能是过度标准化&#34;但它使关系更清晰。

建议的限制并非真正隐藏&#34;因为它们出现在用于定义表的SQL中。我知道您想要从ERD中获取有关数据约束的所有内容,但有时约束过于复杂。

答案 1 :(得分: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

然后,您可以在预订中使用MemberId,Day,PeriodId放置两个唯一索引(这将阻止它们在同一天同时安排)

和一个用于BookableAreaId,Day,PeriodId(这可以防止有人在同一天以相同的15分钟间隔双重预订同一区域)

您也可以将Id字段作为主键放在Bookings表上,并用这些字段上的Primary键替换其中一个Unique索引。

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

ERD

答案 2 :(得分:1)

我会改变你的数据模型:

BookingPeriods将包含时间列表。例如。你可以在早上和下午预订,这将使StartTime上午9点和结束时间下午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