【问题标题】:Query from multiple "Not In" queries without using UNION在不使用 UNION 的情况下从多个“Not In”查询中查询
【发布时间】:2015-05-07 18:32:34
【问题描述】:

很难为我所需要的准确标题。

这围绕着 3 张桌子,是一个预约系统,我需要获取每个医生/护士的名单以及他们空闲的时间段。

我不想在下面的第一个 sql 中使用 UNION,这意味着我必须声明每个医生的姓名,我不想这样做。

表格...

用户详情:

ID    Role   Surname   Clinic
1    Doctor   House      1
2    Doctor   Bob        1
3    Nurse    Smith      1
4    Doctor   Jim        2
5    Nurse    Grant      2 
6    Patient  Billy      1
7    Patient  Jones      1

时隙:

ID   TimeSlot
1     10:00
2     10:30
3     11:00
4     11:30
11    16:30
12    17:00

约会:

ID  StaffID   PatientID  TimeSlot   AppDate
1      1         6          1        today   
2      1         7          3        today
3      2         6          2        today
4      1         6          4       tomorrow

(StaffID 和 PatientID,是用户表中的外键 ID) 我需要一个查询,输出每个时间段和医生/护士,以了解他们今天(或基于“AppDate”的任何一天)没有预约的时间

我可以为特定的医生/护士这样做:

SELECT TimeSlots.TimeSlot, Users.Role, Users.Surname, Users.Clinic 
FROM TimeSlots, Users 
WHERE 
    TimeSlots.ID NOT IN 
        (SELECT Appointments.TimeSlot
        FROM Appointments  
            INNER JOIN Users    
            ON Appointments.MedicalStaffID = Users.ID 
        WHERE AppDate = CONVERT(DATE,GETDATE()) AND Users.Surname = 'House')
AND
    Users.Surname = 'House'
ORDER BY TimeSlots.TimeSlot;

这给了我:

TimeSlot   Role   Surname    Clinic
  10:30   Doctor   House       1
  11:30   Doctor   House       1
  16:30   Doctor   House       1
  17:00   Doctor   House       1

这很好,但我需要 1 个查询来为所有医生/护士显示这个,所以我有:

   TimeSlot   Role   Surname    Clinic
     10:30   Doctor   House       1
     11:30   Doctor   House       1
     16:30   Doctor   House       1
     17:00   Doctor   House       1
     10:00   Doctor   Bob         1
     11:00   Doctor   Bob         1
     11:30   Doctor   Bob         1
     16:30   Doctor   Bob         1
     17:00   Doctor   Bob         1

所以也可以按时间订购。

我最初尝试使用:

SELECT TimeSlots.TimeSlot, Users.Role, Users.Surname, Users.Clinic 
FROM TimeSlots, Users 
WHERE 
    TimeSlots.ID NOT IN (SELECT TimeSlot FROM Appointments  WHERE AppDate = GETDATE() AND (Users.Clinic = 'Werrington') AND (Users.Role = 'Doctor' OR Users.Role = 'Nurse'))
AND
    (Users.Role = 'Doctor' OR Users.Role = 'Nurse')
AND
    (Users.Clinic = 'Werrington')
ORDER BY TimeSlots.TimeSlot;

但这只会输出每个时隙的每个医生

在旁注中,我觉得有一种更好的方法来构建结果表的外观,但我想不出如何。

【问题讨论】:

    标签: sql sql-server-2008 inner-join notin


    【解决方案1】:

    如果我正确理解了这个问题,这应该会给你你想要的......

    SET NOCOUNT ON;
    
    DECLARE @UserDetails TABLE (
        ID      int,
        Role    varchar(50),
        Surname varchar(50),
        Clinic  int )
    
    INSERT @UserDetails VALUES (1, 'Doctor', 'House', 1)
    INSERT @UserDetails VALUES (2, 'Doctor', 'Bob', 1)
    INSERT @UserDetails VALUES (3, 'Nurse', 'Smith', 1)
    INSERT @UserDetails VALUES (4, 'Doctor', 'Jim', 2)
    INSERT @UserDetails VALUES (5, 'Nurse', 'Grant', 2 )
    INSERT @UserDetails VALUES (6, 'Patient', 'Billy', 1)
    INSERT @UserDetails VALUES (7, 'Patient', 'Jones', 1)
    
    DECLARE @TimeSlots TABLE (
        ID          int,
        TimeSlot    varchar(50) )
    
    INSERT @TimeSlots VALUES (1 , '10:00' )
    INSERT @TimeSlots VALUES (2 , '10:30' )
    INSERT @TimeSlots VALUES (3 , '11:00' )
    INSERT @TimeSlots VALUES (4 , '11:30' )
    INSERT @TimeSlots VALUES (11, '16:30' )
    INSERT @TimeSlots VALUES (12, '17:00' )
    
    DECLARE @Appointments TABLE (
        ID          int,
        StaffID     int,
        PatientID   int,
        TimeSlotID  int,
        AppDate     varchar(50) )
    
    INSERT @Appointments VALUES (1, 1, 6, 1, 'today' ) 
    INSERT @Appointments VALUES (2, 1, 7, 3, 'today' )
    INSERT @Appointments VALUES (3, 2, 6, 2, 'today' )
    INSERT @Appointments VALUES (4, 1, 6, 4, 'tomorrow' )
    
    SET NOCOUNT OFF;
    
    WITH CompleteSchedule AS (
        SELECT      UD.ID as UserID, UD.Role, UD.Surname, UD.Clinic, TS.ID as TimeSlotID, TS.TimeSlot
        FROM        @UserDetails UD
        CROSS JOIN  @TimeSlots TS
    )
    SELECT      CS.*
    FROM        CompleteSchedule CS
    LEFT JOIN   @Appointments A ON A.StaffID = CS.UserID AND A.TimeSlotID = CS.TimeSlotID AND A.AppDate = 'today'
    WHERE       A.ID is null
    ORDER BY    CS.UserID, CS.TimeSlotID
    

    CTE 将在每个时间段生成每个员工 X 的“表格”。然后你离开了加入你在给定日期的任命。任何没有约会 ID 的结果行都是开放时间段。

    【讨论】:

    • 您编写的代码很棒并且可以按原样运行,但我只使用了已经创建的数据库并且没有使用过声明。所以我似乎无法让它与我拥有的现有数据库一起运行。我通常只做“USE bd_name”,然后是我的问题中看到的查询。
    • 在 SQL Server 2008 中,我们可以声明 table 类型的变量。由于我无权访问您的数据库,因此我声明了“表变量”来保存数据。将它们视为临时表,您会没事的。您需要做的就是按原样复制我的代码并在查询窗口中运行它,它应该可以正常运行。然后对其进行分析并进行任何必要的更改以引用您的真实表格。 (例如,我怀疑您的AppDate 列是否真的包含“今天”和“明天”。)
    • 啊,没关系,我的问题中有一些与我实际拥有的名称不同的名称,所以它正在抛出 wobblies。还必须在 WHERE 中添加“AND CS.Role != 'Patients'”,但这是一个小小的疏忽,非常感谢,让它工作并学习了一些新的 sql 魔法:)
    猜你喜欢
    • 2014-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多