【问题标题】:SQL Interview: Prevent overlapping date rangeSQL 面试:防止日期范围重叠
【发布时间】:2016-10-01 11:51:33
【问题描述】:

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

如果 经理:A 与2016-01-01 11:00 to 2016-01-01 14:00Employee-1 有约会 那么如果Employee-2(或其他员工)尝试从20-16-01-01 13:00 to 16:00预约,那么它不应该允许。

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

【问题讨论】:

  • 要强制执行此约束,您需要触发器或用户定义的函数(至少在大多数数据库中)。
  • 如果这真的是一个 SQL 面试问题,您可以简单地回答在设计时这是不可能的。
  • 你可以在 SQL Server 中执行此操作,如果你还对空闲时间段进行建模,具有将每个时间段链接到其前任和后继的交叉引用外键,并编写一些真正可怕的 @987654325 @ 管理插入/删除的语句(通常情况下,您需要通过更新一个、插入一个新行并插入新约会来分割一个空闲期,所有这些都在一个语句中,以便外键保持满足)。这是可行的,但通常成本高于价值。

标签: sql create-table check-constraints


【解决方案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)
)

我知道这不完全符合您的表格的开始和结束时间的前提,但如果您可以控制表格结构,这将起作用。

【讨论】:

    【解决方案2】:

    CHECK CONSTRAINT + FUNCTION(这是我能得到的 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')
    

    触发器:

    我尽量避免触发。它们本身并不邪恶——但它们确实为您的应用程序增加了一层新的复杂性。如果无法避免,则需要 INSTEAD OF INSERT 和 INSTEAD OF UPDATE(大概)。技术网参考:https://technet.microsoft.com/en-us/library/ms179288%28v=sql.105%29.aspx

    请记住,如果您拒绝插入/更新尝试,您是否需要或如何将其传达给用户。

    存储过程/用户界面:

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

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

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

    如果 proc 向 UI 返回失败,则在 UI 中通过重新查询所有各方的可见时间表进行处理,并伴有错误消息。

    【讨论】:

    • 注意:问题是关于(检查)约束、数据建模和 SQL 中的 DDL。应用程序或 UI 在这里无关紧要,存储过程也是如此。
    • @wildplasser -- 在答案中添加了一个 CHECK CONSTRAINT 选项......不完全是 DDL,但......更接近。
    【解决方案3】:

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

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

    我想要两张桌子。第一个表根据组织的业务需求将一天分成几部分(片)。每个切片都是该表的主键。我个人会选择相当于 96 天的 15 分钟片。当用户选择会议的实际开始时间和实际结束时间时,该表中的每一天部分将具有将由调度应用程序引用的“块开始”和“块结束”时间。应用程序需要在 3 个“AND”语句之间应用诸如两个“OR”运算符之类的逻辑,以查看是否将特定的 blockID 插入到您的 Appointments 表中:

    • 实际开始 >= 块开始 AND 实际开始
    • 实际结束>块开始和实际结束
    • 实际开始块结束

    这与 Chris Steele 的回答略有不同,因为它使用两个表。实际的时间戳仍然可以插入到您的应用程序表中,但只有在与 TimeBlocks 表进行比较时才会对它们应用逻辑。在我的约会表中,我更喜欢将日期分解为组成部分以进行跨平台分析(我们的组织使用多个 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)
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-31
      相关资源
      最近更新 更多