从日历表在sql server中获取工作日

时间:2016-04-12 05:55:53

标签: sql sql-server

我有两张桌子

一个是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

我怎样才能逐年进行这些活动?

谢谢!

2 个答案:

答案 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,并且无法利用索引来提高性能。