0

下面的 SQL 查询应该显示教师的可用性。有 4 种可能的预订类型 - 上午、下午、全天和每小时。如果有上午预订,则单元格中的文本应显示 PM,如果有 PM 预订,则应显示 AM,如果有全天预订,或上午和下午预订,则应显示“xxx”。这一切都很好。

现在,我继续按小时预订。可以安全地假设每天只有 2 小时的预订,上午 1 次(开始时间 <= 12 点)和下午 1 次(结束时间 > 12 点),这意味着我们应该显示“xxx”。然而,我真的很难让这个表现出来。

WITH Bookings AS
(   SELECT  TeacherID,
            [WeekDay] = DATENAME(WEEKDAY, BookingDate),
            [Status] = CASE 
                            WHEN [3] > 1 THEN 'XXX'
                            WHEN ([0] > 0 AND [1] > 0) THEN 'XXX'
                            WHEN [2] > 0 THEN 'XXX'                            
                            WHEN [0] > 0 THEN 'PM'
                            WHEN [1] > 0 THEN 'AM'
                            WHEN [3] > 0 AND CONVERT(time(0), EndTime) <= CONVERT(time(0), '12:00:00') THEN 'PM'
                            WHEN [3] > 0 AND CONVERT(time(0), StartTime) >= CONVERT(time(0), '12:00:00') THEN 'AM'
                            WHEN [3] > 0 AND CONVERT(time(0), StartTime) <= CONVERT(time(0), '12:00:00') AND CONVERT(time(0), EndTime) >= CONVERT(time(0), '12:00:00') THEN 'XXX'                           
                        END
    FROM    (   SELECT  TeacherID, BookingDate, BookingDuration, StartTime, EndTime, [x] = 1
                FROM    BookingDays where (Status = 0 or Status IS NULL)
            ) BookingDays
            PIVOT
            (   SUM(x)
                FOR BookingDuration IN ([0], [1], [2], [3])
            ) pvt

             WHERE BookingDate >= DATEADD(ww, DATEDIFF(ww,0,'04/22/2013'), 0) AND BookingDate <= DATEADD(ww, DATEDIFF(ww,0,'04/22/2013'), 6)

), PivotedBookings AS
(   SELECT  *
    FROM    Bookings
            PIVOT
            (   MAX([Status])
                FOR [WeekDay] IN ([Monday], [Tuesday], [Wednesday], [Thursday], [Friday])
            ) pvt

)
SELECT ID,Firstname,Surname,Band,'£' + CONVERT(varchar(50),DefaultChargeRateDaily) + '/' + '£' + CONVERT(varchar(50), DefaultPayRateDaily) as 'BandRates',Telephone,Mobile,Teacher,TeacherAssistant,KeyStage,MAX(Monday) Monday,MAX(Tuesday) Tuesday,MAX(Wednesday) Wednesday,MAX(Thursday) Thursday,MAX(Friday) Friday, Notes
  FROM (
SELECT  t.ID, 
        t.Firstname, 
        t.Surname, 
        tb.Band,
        t.DefaultChargeRateDaily,
        t.DefaultPayRateDaily,
        t.Telephone,
        t.Mobile,
        t.Teacher,
        t.TeacherAssistant,
        CASE WHEN t.Nursery > 0 THEN 'NUR' WHEN t.Reception > 0 THEN 'REC' WHEN t.Year1 > 0 THEN 'Y1' WHEN t.Year2 > 0 THEN 'Y2' WHEN t.Year3 > 0 THEN 'Y3' WHEN t.Year4 > 0 THEN 'Y4' WHEN t.Year5 > 0 THEN 'Y5' WHEN t.Year6 > 0 THEN 'Y6' WHEN t.Year7 > 0 THEN 'Y7' WHEN t.Year8 > 0 THEN 'Y8' WHEN t.Year9 > 0 THEN 'Y9' WHEN t.Year10 > 0 THEN 'Y10' WHEN t.Year11 > 0 THEN 'Y11' WHEN t.ALevel > 0 THEN 'ALevel' END + ' - ' + CASE WHEN t.ALevel > 0 THEN 'ALevel' WHEN t.Year11 > 0 THEN 'Y11' WHEN t.Year10 > 0 THEN 'Y10' WHEN t.Year9 > 0 THEN 'Y9' WHEN t.Year8 > 0 THEN 'Y7' WHEN t.Year6 > 0 THEN 'Y6' WHEN t.Year5 > 0 THEN 'Y6' WHEN t.Year4 > 0 THEN 'Y4' WHEN t.Year3 > 0 THEN 'Y3' WHEN t.Year2 > 0 THEN 'Y2' WHEN t.Year1 > 0 THEN 'Y1' WHEN t.Reception > 0 THEN 'REC' WHEN t.Nursery > 0 THEN 'NUR' ELSE '' END as 'KeyStage',

        Monday = CASE WHEN an.Date = DATEADD(ww, DATEDIFF(ww,0,'04/22/2013'), 0) AND an.TeacherID = t.ID THEN an.Text WHEN t.Status = 0 THEN 'XXX'  ELSE COALESCE(pb.Monday, '') END,
        Tuesday = CASE WHEN an.Date = DATEADD(ww, DATEDIFF(ww,0,'04/22/2013'), 1) AND an.TeacherID = t.ID THEN an.Text WHEN t.Status = 0 THEN 'XXX'  ELSE COALESCE(pb.Tuesday, '') END,
        Wednesday = CASE WHEN an.Date = DATEADD(ww, DATEDIFF(ww,0,'04/22/2013'), 2) AND an.TeacherID = t.ID THEN an.Text WHEN t.Status = 0 THEN 'XXX'  ELSE COALESCE(pb.Wednesday, '') END,
        Thursday = CASE WHEN an.Date = DATEADD(ww, DATEDIFF(ww,0,'04/22/2013'), 3) AND an.TeacherID = t.ID THEN an.Text WHEN t.Status = 0 THEN 'XXX'  ELSE COALESCE(pb.Thursday, '') END,
        Friday = CASE WHEN an.Date = DATEADD(ww, DATEDIFF(ww,0,'04/22/2013'), 4) AND an.TeacherID = t.ID THEN an.Text WHEN t.Status = 0 THEN 'XXX'  ELSE COALESCE(pb.Friday, '') END,
        Notes
FROM    Teachers t

        LEFT JOIN PivotedBookings pb
            ON pb.TeacherID = t.ID
        LEFT JOIN TeacherBands tb
            ON tb.ID = t.Band
        LEFT JOIN AvailabilityNotes an 
            ON t.ID = an.TeacherID
            WHERE t.Active = 0 and (t.Status = 1 or t.Status = 0) and t.PrimarySchool = 1
            ) T1
 GROUP BY ID,Firstname,Surname,Telephone,Mobile,Teacher,TeacherAssistant,KeyStage,Notes,DefaultChargeRateDaily,DefaultPayRateDaily,Band
 ORDER BY Surname,Firstname asc

第一部分生成以下内容 -

SELECT  TeacherID,
            [WeekDay] = DATENAME(WEEKDAY, BookingDate),
            [Status] = CASE 
                            WHEN [3] > 1 THEN 'XXX'
                            WHEN ([0] > 0 AND [1] > 0) THEN 'XXX'
                            WHEN [2] > 0 THEN 'XXX'                            
                            WHEN [0] > 0 THEN 'PM'
                            WHEN [1] > 0 THEN 'AM'
                            WHEN [3] > 0 AND CONVERT(time(0), EndTime) <= CONVERT(time(0), '12:00:00') THEN 'PM'
                            WHEN [3] > 0 AND CONVERT(time(0), StartTime) >= CONVERT(time(0), '12:00:00') THEN 'AM'
                            WHEN [3] > 0 AND CONVERT(time(0), StartTime) <= CONVERT(time(0), '12:00:00') AND CONVERT(time(0), EndTime) >= CONVERT(time(0), '12:00:00') THEN 'XXX'                           
                        END
    FROM    (   SELECT  TeacherID, BookingDate, BookingDuration, StartTime, EndTime, [x] = 1
                FROM    BookingDays where (Status = 0 or Status IS NULL)
            ) BookingDays
            PIVOT
            (   SUM(x)
                FOR BookingDuration IN ([0], [1], [2], [3])
            ) pvt

             WHERE BookingDate >= DATEADD(ww, DATEDIFF(ww,0,'04/22/2013'), 0) AND BookingDate <= DATEADD(ww, DATEDIFF(ww,0,'04/22/2013'), 6)

表列:

TeacherID | WeekDay   | Status
9386    Monday      PM
9386    Tuesday     AM
9386    Wednesday   XXX
9763    Monday      PM
9763    Tuesday     AM
9763    Wednesday   XXX
9927    Monday      PM
9927    Tuesday     AM
9927    Wednesday   XXX
10358   Monday      PM
10358   Monday      AM

我们可以在这里看到,最后两行需要合并并在状态列中显示为 XXX。

下面的屏幕截图中显示了一个示例。黄色突出显示,显示 PM。但是,有 2 小时预订(BookingDuration ID 3),一个是上午 10:00 - 上午 11:00,另一个是 14:00 - 15:00。因此,这应该显示 XXX,而不是 PM/AM。

截屏

我希望这是有道理的!

4

1 回答 1

1

你的问题可以追溯到第一个查询:

FROM    (   SELECT  TeacherID, BookingDate, BookingDuration, StartTime, EndTime, [x] = 1
            FROM    BookingDays 
            WHERE   (Status = 0 OR Status IS NULL)
        ) BookingDays
        PIVOT
        (   SUM(x)
            FOR BookingDuration IN ([0], [1], [2], [3])
        ) pvt

这样做的想法是获得一个输出,其中每位教师每天有一行,在子查询中添加StartTimeEndTime后,不能保证您每天每位教师都会得到一行,因为两条记录可能有不同的开始/同一日期的结束时间,为了解决这个问题,您可以使用:

| TeacherID | BookingDate | BookingDuration | StartTime | EndTime |
|-----------+-------------+-----------------+-----------+---------|
|    1      |  20130422   |        3        |   10:00   |  11:00  |
|    1      |  20130422   |        3        |   13:00   |  14:00  |

在预订 CTE 中,这将返回(如果您将开始/结束时间添加到选择列表,但删除它们不会使其成为一行):

| TeacherID | WeekDay | Status | StartTime | EndTime |
|-----------+---------|--------+-----------+---------|
|    1      |  Monday |   'AM' |   10:00   |  11:00  |
|    1      |  Monday |   'PM' |   13:00   |  14:00  |

如果您使用以下

FROM    (   SELECT  TeacherID, 
                    BookingDate, 
                    BookingDuration, 
                    StartTime = MIN(StartTime) OVER(PARTITION BY TeacherID, BookingDate),
                    EndTime = MIN(StartTime) OVER(PARTITION BY TeacherID, BookingDate)
                    [x] = 1
            FROM    BookingDays 
            WHERE   (Status = 0 OR Status IS NULL)
        ) BookingDays
        PIVOT
        (   SUM(x)
            FOR BookingDuration IN ([0], [1], [2], [3])
        ) pvt

使用窗口函数,您可以确保每个教师/天组合只返回相同的 StartTime 和 EndTime,您将获得:

| TeacherID | WeekDay | Status | StartTime | EndTime |
|-----------+---------|--------+-----------+---------|
|    1      |  Monday |  'XXX' |   10:00   |  14:00  |

然后,您以后不需要在查询中合并行。

您需要进行的另一项更改是Status稍微更改 CASE 语句,以便获得完整的查询:

WITH Bookings AS
(   SELECT  TeacherID,
            [WeekDay] = DATENAME(WEEKDAY, BookingDate),
            [Status] = CASE 
                            WHEN ([0] > 0 AND [1] > 0) THEN 'XXX'
                            WHEN [2] > 0 THEN 'XXX'                            
                            WHEN [0] > 0 THEN 'PM'
                            WHEN [1] > 0 THEN 'AM'
                            WHEN [3] > 0 AND StartTime <= CONVERT(TIME, '12:00:00') AND EndTime >= CONVERT(TIME, '12:00:00') THEN 'XXX'   
                            WHEN [3] > 0 AND EndTime <= CONVERT(TIME, '12:00:00') THEN 'PM'
                            WHEN [3] > 0 AND StartTime >= CONVERT(TIME, '12:00:00') THEN 'AM'                        
                        END
    FROM    (   SELECT  TeacherID, 
                        BookingDate, 
                        BookingDuration, 
                        StartTime = CAST(MIN(StartTime) OVER(PARTITION BY TeacherID, BookingDate, BookingDuration) AS TIME),
                        EndTime = CAST(MAX(EndTime) OVER(PARTITION BY TeacherID, BookingDate, BookingDuration) AS TIME),
                        [x] = 1
                FROM    BookingDays 
                WHERE   (Status = 0 OR Status IS NULL)
            ) BookingDays
            PIVOT
            (   SUM(x)
                FOR BookingDuration IN ([0], [1], [2], [3])
            ) pvt
)

我在这里所做的就是删除这条线WHEN [3] > 1,以防万一两个小时的时段都发生在上午,或者都发生在下午(我知道你已经说过假设这不会发生是安全的,但为了完整起见,我已添加),并且我将以下行移到了更高的位置:

WHEN [3] > 0 AND StartTime <= CONVERT(TIME, '12:00:00') AND EndTime >= CONVERT(TIME, '12:00:00') THEN 'XXX'   

这应该是获取所需格式的数据所需的所有更改。

SQL Fiddle 示例(注老师 5)

编辑

正如您所说,如果早上有一个小时时段,下午有一个时段,或者反过来,上述方法将失败。我认为,如果您将案例陈述更改为以下内容,这应该可以解决问题。

        [Status] = CASE 
                        WHEN ([0] > 0 AND [1] > 0) THEN 'XXX'
                        WHEN [2] > 0 THEN 'XXX'    
                        WHEN [3] > 0 AND StartTime <= CONVERT(TIME, '12:00:00') AND EndTime >= CONVERT(TIME, '12:00:00') THEN 'XXX' 
                        WHEN [3] > 0 AND StartTime <= CONVERT(TIME, '12:00:00') AND [1] > 0 THEN 'XXX'          
                        WHEN [3] > 0 AND StartTime >= CONVERT(TIME, '12:00:00') AND [0] > 0 THEN 'XXX'
                        WHEN [0] > 0 THEN 'PM'
                        WHEN [1] > 0 THEN 'AM'  
                        WHEN [3] > 0 AND EndTime <= CONVERT(TIME, '12:00:00') THEN 'PM'
                        WHEN [3] > 0 AND StartTime >= CONVERT(TIME, '12:00:00') THEN 'AM'                        
                    END
于 2013-04-22T15:50:34.617 回答