以下SQL查询应该显示教师可用性。有4种可能的预订类型 - 上午,下午,全天和每小时。如果有AM预订,单元格中的文本应显示PM,如果有PM预订,则应显示AM,如果有全天预订,或者AM和PM预订,则应显示'xxx'。一切正常。
现在,我继续进行每小时预订。可以安全地假设每天只有2小时预订,AM为1(开始时间<= 12pm),PM为1(结束时间> 12pm),这意味着我们应该显示'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。
我希望这是有道理的!
答案 0 :(得分: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
这样做的想法是获得一个输出,即每个教师每天有一行,在子查询中添加StartTime
和EndTime
,不能保证你会得到一行每位教师每天,因为两个记录可能在同一日期有不同的开始/结束时间,为了解决这个问题,您可以使用:
| 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
,以防万一发生在AM中,或两者都发生在PM中(我知道你已经说过可以安全地假设这一点不会发生,但为了完整性,我已经添加了它),并且我已经将以下行更高了:
WHEN [3] > 0 AND StartTime <= CONVERT(TIME, '12:00:00') AND EndTime >= CONVERT(TIME, '12:00:00') THEN 'XXX'
这应该是以您需要的格式获取数据所需的所有更改。
Example on 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