Sql 数据库关系多对多3向混淆

Sql 数据库关系多对多3向混淆,sql,sql-server,database,sql-server-2008,relational-database,Sql,Sql Server,Database,Sql Server 2008,Relational Database,我有一个简单的数据库a,我想创建一个预订和日程安排系统。它是开放的改变,以达到我的目标,所以不要担心改变设计,如果需要的话 以下是ERD: 问题如下: 我有一些成员可以在特定时间(预订期)预订特定地点(可预订区域)。当前关系集允许许多成员在多个地点多次预订,这些可能会重叠。i、 e.允许双重预订或同时预订两个位置(即同时在两个位置) 我的问题是,如何修改此数据库的设计,以严格允许以下内容: 会员只能预订一个地点,但可以多次预订(即9-9:30、9:30-10、10-10:30等)。有效地允许会

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

以下是ERD:

问题如下: 我有一些成员可以在特定时间(预订期)预订特定地点(可预订区域)。当前关系集允许许多成员在多个地点多次预订,这些可能会重叠。i、 e.允许双重预订或同时预订两个位置(即同时在两个位置)

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

要实现这一点,我需要改变什么。我更喜欢在关系中这样做,只是因为这让它变得显而易见,然而,作为最后的手段,如果没有办法用关系来做,我会求助于触发器,但我不想使用它们,因为它们不像erd那么明显

提前感谢您的帮助

编辑1:触发器和检查约束确实是可接受的答案,我并不是说这不是标准或不正确。如果这是我能做到的唯一方法,那么我只能这样做。然而,我之所以这样问,是因为我更愿意让其他程序员尽可能清楚地认识到这一点,这就是为什么我在寻找一种通过关系来实现这一点的方法。然而,我承认这可能是不可能的。我只是不确定,回答这个问题


编辑2:我知道我说过我想在不使用约束或触发器的情况下完成这项工作,但是如果没有extream措施(这将使事情变得过于复杂),似乎不可能完成这项工作。然而,我确实喜欢这个过于复杂的答案,因为它展示了一些关于人际关系的真正美好的想法。谢谢大家。

原始回复

如果我理解正确,下面的场景显示了哪些是允许的,哪些是不允许的

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
好的,在你写我之前,请听我说完!您的图表包含这些表的4/6。我建议将会员、预订时间和预订地点之间的关系分开

下面有一个代理主键和一个复合唯一键,以保证一段时间内没有成员被双重预订

Member_BookTime
---------------
ID (PK)
Member_ID (CUK)
BookTime_ID (CUK)
BookPlace_BookTime_ID
------------------
ID (PK)
BookPlace_ID (CUK)
BookTime_ID (CUK)
下面有一个代理主键和一个复合唯一键,以保证一段时间内没有房间被重复预订

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可见,但有时约束太复杂。

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

periods表如下所示:

   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表上的主键,并用这些字段上的主键替换其中一个唯一索引

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


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

BookingPeriods将包含一个时间段列表。例如您可以在上午和下午预订,即上午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 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

你的建议是正确的。为了澄清,您是否建议我在bookings.bookingperiodid和bookings.bookableareaid上放置唯一键,然后添加一个单独的主键来标识每个预订。如果是的话,你确定这会满足我的要求吗。同样,唯一关键点本质上是隐藏约束的另一种形式。我并不反对,但我宁愿不使用。但是,如果没有其他选项