我有两张桌子
一个是2010年1月份明智的学校假期列表,其他是日历表。
我想在2010年1月计算所有三所学校的工作日数据。
我从真正的问题中取了一个很小的例子。
假期表
SchoolID HolidayOn
1 01-01-2010
1 02-01-2010
2 01-01-2010
2 02-01-2010
3 01-01-2010
3 02-01-2010
3 03-01-2010
我想要所有三所学校的工作日
输出应该是这样的
SchoolID WorkingDays
1 03-01-2010
1 04-01-2010
1 05-01-2010
1 06-01-2010
.
.
.
.
1 31-01-2010
2 03-01-2010
2 04-01-2010
2 05-01-2010
2 06-01-2010
.
.
.
2 31-01-2010
3 04-01-2010
3 05-01-2010
3 06-01-2010
3 07-01-2010
.
.
.
.
3 31-01-2010
我尝试过这样的事情
SELECT C.CalendarDate, H.HolidayOn
FROM Calendar as C LEFT OUTER JOIN Holidays as H
ON C.CalendarDate = H.HolidayOn
WHERE H.HolidayOn IS NULL
AND YEAR(C.CalendarDate) IN (2011)
ORDER BY C.CalendarDate
我怎样才能逐年进行这些活动?
谢谢!
答案 0 :(得分:0)
首先,从SchoolID
表中获取所有不同的Holidays
。然后在CROSS JOIN
表上执行Calendar
以生成学校和日历日期的所有组合。然后使用NOT EXISTS
过滤假期。
SELECT
s.SchoolID,
c.CalendarDate
FROM(
SELECT DISTINCT SchoolID FROM Holidays
)s
CROSS JOIN Calendar c
WHERE
NOT EXISTS(
SELECT 1
FROM Holidays h
WHERE
h.SchoolID = s.SchooldID
AND h.HolidayOn = c.CalendarDate
)
AND c.CalendarDate >= '20110101'
AND c.CalendarDate < '20120101'
避免使用YEAR(CalendarDate)
,因为它会阻止您的查询使用索引。而是使用>=
和<
。
答案 1 :(得分:0)
如果您拥有所有学校的所有日期,那么这只是一个简单的问题:
SELECT d.SchoolId, d.CalendarDate
FROM AllDatesAllSchools d
EXCEPT
SELECT h.SchoolId, h.HolidayOn
FROM HolidayDates
但是,你只有所有日期;并非所有学校的所有日期。所以你首先通过在Calendar和AllSchools上作为CTE进行交叉连接来制作它:
;WITH AllSchools AS (
SELECT DISTINCT SchoolId
FROM Holidays
), AllDatesAllSchools AS (
SELECT h.SchoolId, d.CalendarDate
FROM Holidays h
CROSS JOIN Calendar d
)
SELECT d.SchoolId, d.CalendarDate
FROM AllDatesAllSchools d
WHERE d.CalendarDate >= '20110101'
AND d.CalendarDate < '20120101'
EXCEPT
SELECT h.SchoolId, h.HolidayOn
FROM Holidays h
注意:请注意我在特定年份过滤CalendarDate的方式非常慎重。使用YEAR(d.CalendarDate)
会使查询成为非SARGable,并且无法利用索引来提高性能。