SQL访谈:防止重叠日期范围

时间:2016-06-01 22:52:39

标签: sql create-table check-constraints

假设有一个使用startDatetime和endDatetime的管理者(或HR)列表的一个appointment_booking表,那么如何仔细设计该表,以便它不接受下一个与同一经理重叠的条目,如果他/她有与其他人约会。

如果 经理:A 约会2016-01-01 11:00 to 2016-01-01 14:00Employee-1 然后,如果Employee-2(或其他员工)试图从20-16-01-01 13:00 to 16:00预约,则不应允许。

注意:这是关于设计表格,因此不鼓励触发器/程序。

3 个答案:

答案 0 :(得分:1)

您可以插入时间片段,而不是插入范围。您可以根据需要制作切片,但假装您可以一次预订30分钟的经理。要从11:30到12:00预订,您需要在11:30插入一行时间值。要从11:30到12:30预订,您需要插入两行,一行在11:30,另一行在12:00。然后,您可以使用主键约束或唯一约束来防止过度预订。

create table appointment_booking (
    manager char not null,
    startSlice DateTime,
    visiting_employee varchar2(255),
    primary key (manager, startSlice)
)

我知道这并不完全符合你的表的开头和结束时间的前提,但是如果你能控制表结构,那就行了。

答案 1 :(得分:0)

检查约束+功能(这与我可以获得DDL答案一样接近)

你可以创建一个标量函数 - “SCHEDULE_OPENING_EXISTS()”,它将begin,end,employeeID作为输入,输出true或false。

然后你可以在表格上创建一个检查约束

CREATE TABLE...
    WITH CHECK ADD CONSTRAINT OPENING_EXISTS
    CHECK (SCHEDULE_OPENING_EXISTS(begin, end, employeeID)) = 'True')

TRIGGERS:

我尽力避免使用触发器。它们本身并不邪恶 - 但它们确实为您的应用程序添加了一层新的复杂性。如果你无法避免它,你将需要一个INSTEAD OF INSERT,并且还需要一个INSTEAD OF UPDATE(大概)。 Technet参考文献:https://technet.microsoft.com/en-us/library/ms179288%28v=sql.105%29.aspx

请注意,如果您拒绝插入/更新尝试,是否需要或如何将该信息传达回用户。

存储程序/用户界面:

存储过程是否适用于您的情况?示例场景:

  1. 用户界面 - 用户需要查看他们安排约会的人员的日程安排。

  2. 从UI - 尝试使用存储过程进行插入/更新。让它重新检查(最后一刻)开头(如果开头不再存在则返回失败),然后如果开头仍然存在则有条件地插入/更新(返回成功消息)。

  3. 如果proc向UI返回失败,请通过重新查询所有各方的可见时间表来处理UI,并附带错误消息。

答案 2 :(得分:0)

我认为这些类型的问题很有意思,因为每当您设计数据库时,了解将与您的数据库交互的应用程序的要求非常重要。

话虽如此,只要应用程序可以引用多个表格,我认为Chris Steele的回答是一个很好的开始,我将在此基础上构建......

我想要2张桌子。第一个表将一天划分为多个部分(切片),具体取决于组织的业务需求。每个切片都是该表的主键。我个人会选择相当于96天零件的15分钟切片。该表中的每一天都有一个"块开始"和一个"块结束"当用户选择实际开始时间和会议的实际结束时间时,调度应用程序将引用的时间。应用程序需要应用逻辑,例如两个" OR" 3" AND"之间的运营商语句,以查看是否将特定的blockID插入到约会表中:

  • 实际开始> =块开始和实际开始<阻止结束
  • 实际结束>块开始和实际结束<阻止结束
  • 实际开始<块开始和实际结束>阻止结束

这与Chris Steele的答案略有不同,因为它使用了两张桌子。实际时间戳仍然可以插入应用程序表中,但逻辑仅在与TimeBlocks表进行比较时应用于它们。在我的Appointments表中,我更喜欢将日期分为跨平台分析的组成部分(我们的组织使用多个RDBMS以及SAS进行分析):

CREATE TABLE TimeBlocks (
          blockID Number(X) NOT NULL,
          blockStart DateTime NOT NULL,
          blockEnd DateTime NOT NULL,
     primary key (blockID)
);


CREATE TABLE Appointments (
          mgrID INT NOT NULL,
          yr INT NOT NULL,
          mnth INT NOT NULL,
          day INT NOT NULL,
          blockID INT NOT NULL,
          ApptStart DateTime NOT NULL,
          ApptEnd DateTime NOT NULL
          empID INT NOT NULL,
     primary key (mgrID, yr, mnth, day, blockID),
     CONSTRAINT timecheck
          check (ApptStart < ApptEnd)
);