Slot Time Challenge - 医生预约数据库架构

the*_*heK 13 schema database-design sql-server

我正在尝试建立一个医生预约系统,在线患者将有两个选择:

  1. 第一次访问(这次访问应该是 20 分钟)
  2. 跟进访问(此访问应为 10 分钟)

约束:

  1. 价格会根据第一次/后续枯萎而有所不同
  2. 医生可能在插槽之间有休息时间
  3. 系统界面将在预订插槽时支持这两个选项
  4. 我们需要插槽之间的最小间隙时间才能达到最大值。医生可用性的使用

到目前为止我们完成的模型是基于创建一个如下所示的 Doctor Slot 表 Doctor Slots 表架构

如果 DoctorSlot 为 N 且 N=10 分钟,请考虑以下示例

案例 第一次 if(N*2)== Free 保留块两个插槽而不是一个

案例跟进 if(N)==Free Make Reservation Block 1 slot

示例医生:9:00 至 9:10 医生:9:10 至 9:20 医生:9:20 至 9:30

病例首次向患者展示 9:00 至 9:20

挑战:

  • 附加时间从 9:00 到 9:20(医生的插槽之间可能有一个缓冲时间(医生休息))
  • 我们将从数据库中获得两个插槽 ID 而不是一个(哪个 SlotID 将与 Order 一起使用)
  • 如何在运行时根据用户的情况向用户显示我们将在哪个时间使用通用模型并相应地稍后更新价格
  • 如果用户预订了第一个时间段,然后另一个用户预订了跟进,则会出现间隙以及如何在数据库中的 SQL Server 中处理时间

问题:

  1. 实现满足所有可能场景的解决方案的最佳数据库模式是什么?
  2. 处理来自 SQL Server/ASP.NET POV 的时间实体的最佳方法是什么?

men*_*osi 7

我建议使用一个Appointment表格来存储每个医生的当前预约。我们可以在此表上添加一些约束,将约会开始时间限制为甚至十分钟(例如 9.00、9.10、9.20),并添加一些其他常识检查,例如EndTimeafterStartTime和医生不能同时开始两个约会. 假设您还希望医生只在上午 9 点到下午 5 点之间工作,因为每个人都需要一些工作与生活的平衡。

CREATE TABLE Appointment (
    DoctorID char(1) NOT NULL,
    [Date] date NOT NULL,
    StartTime time(0) NOT NULL CONSTRAINT CHK_StartTime_TenMinute CHECK (DATEPART(MINUTE, StartTime)%10 = 0 AND DATEPART(SECOND, StartTime) = 0),
    EndTime time(0) NOT NULL CONSTRAINT CHK_EndTime_TenMinute CHECK (DATEPART(MINUTE, EndTime)%10 = 0 AND DATEPART(SECOND, EndTime) = 0),
    Status char(1) NOT NULL,
    UserID char(1) NOT NULL,
    Price int NOT NULL,
    CONSTRAINT PK_Appointment PRIMARY KEY CLUSTERED (DoctorID, [Date], StartTime),
    CONSTRAINT CHK_StartTime_BusinessHours CHECK (DATEPART(HOUR, StartTime) > = 9 AND DATEPART(HOUR, StartTime) < = 16),
    CONSTRAINT CHK_EndTime_BusinessHours CHECK (DATEPART(HOUR, EndTime) > = 9 AND DATEPART(HOUR, DATEADD(SECOND, -1, EndTime)) < = 16),
    CONSTRAINT CHK_EndTime_After_StartTime CHECK (EndTime > StartTime));
CREATE INDEX iDoctor_End ON Appointment (DoctorID, [Date], EndTime);
Run Code Online (Sandbox Code Playgroud)

我们可以在这个表中插入一些数据,看看它是什么样子的。请注意,第三次插入将失败,因为它被我们的约束阻止了。医生不能同时预约两次。

INSERT INTO Appointment VALUES ('A', '20170420', '09:00:00', '09:10:00', 'P', '1', '0');
INSERT INTO Appointment VALUES ('A', '20170420', '09:20:00', '09:40:00', 'C', '2', '10');
INSERT INTO Appointment VALUES ('A', '20170420', '09:00:00', '09:20:00', 'C', '2', '10');
Run Code Online (Sandbox Code Playgroud)

假设您有一个数字表。如果你没有很多其他人已经描述了如何创建一个。如果所有其他方法都失败了,这可以为您创建一个,但这可能不是最好的方法。

CREATE TABLE Numbers (Number int PRIMARY KEY CLUSTERED);
DECLARE @number int = 0;
WHILE @number < 1000
BEGIN
    INSERT INTO Numbers VALUES (@number);
    SET @number += 1;
END 
Run Code Online (Sandbox Code Playgroud)

现在,如果我们想查看特定医生的空闲槽位,我们需要做的就是指定哪个医生,以及我们要查找的槽位多长时间:

DECLARE @doctorID char(1) = 'A';
DECLARE @length tinyint = 20;
WITH Slots AS (
    SELECT StartTime = DATEADD(MINUTE, ((DATEPART(MINUTE, GETDATE())/10)+1+Number)*10, DATEADD(HOUR, DATEPART(HOUR, GETDATE()), CONVERT(smalldatetime, CONVERT(date, GETDATE())))),
           EndTime = DATEADD(MINUTE, @length, DATEADD(MINUTE, ((DATEPART(MINUTE, GETDATE())/10)+1+Number)*10, DATEADD(HOUR, DATEPART(HOUR, GETDATE()), CONVERT(smalldatetime, CONVERT(date, GETDATE())))))
      FROM Numbers)
SELECT TOP 15 DoctorID = @doctorID,
    s.StartTime,
    s.EndTime
  FROM Slots AS s
  WHERE NOT EXISTS (SELECT 1 
                      FROM Appointment AS a
                      WHERE (CONVERT(time(0), s.StartTime) < a.EndTime AND CONVERT(time(0), s.EndTime) > a.StartTime)
                        AND a.DoctorID = @doctorID
                        AND a.[Date] = CONVERT(date, s.StartTime))
    AND DATEPART(HOUR, s.StartTime) >= 9
    AND DATEPART(HOUR, DATEADD(MINUTE, -1, s.EndTime)) <= 16
ORDER BY s.StartTime;
Run Code Online (Sandbox Code Playgroud)

这看起来有点尴尬,所以如果有人可以改进日期逻辑,很乐意接受建议。

如果医生想要休息,请将休息时间作为预约输入,并且无法进行预订。

请注意,表约束不强制执行非重叠约会。这是可能的,但它更复杂。如果这是我的系统,我会考虑一些系统(例如触发器)来最终验证该约会在插入时与现有约会不重叠,但这取决于您。

  • @user3291143是的,我注意到这是一个老问题,但它被提到了首页,所以我认为值得尝试一个更彻底的答案以供将来参考。感谢您的回复。 (2认同)