如何使用日历参考 table 从 SQL 服务器中的给定日期计算工作日

How to count business days from a given date in SQL Server using a calendar reference table

我有两个 table。一个 table 是具有 date 列和 kindofday 列的日历。 kindofday 列包含 'bankday'、'saturday'、'sunday' 和 'holiday'。我需要考虑假期,否则网上有几个有用的查询...

        date                          kindofday
1999-08-24 00:00:00:000                bankday

我正在努力构建一个可以计算从给定日期算起的工作日数的查询。类似于:

Select [date] + 12 business days。我不确定如何使用日历 table 作为参考 - 本质上我需要在此日历 table 中找到一个日期,然后对该列倒计时数个工作日并提取该日期。我把它放在一个函数中,所以不用担心复杂性。可能有一个愚蠢的简单解决方案,我只是没有看到。

我愿意接受任何考虑假期的解决方案,即使他们不使用我的日历 table。我可以更改日历 table 但是我需要这样做才能使这项工作...即:使用 binary 而不是 string 'bankday' 等...

我试过这个:我从日历中删除了所有非银行日并添加了一个 integer 键,然后 set @date = (select key from calendar where @date=[date] 然后将工作日的数量添加到该键并返回日期,但问题是当 @date 是非银行日时它不会在日历中找到匹配项 table...

将问题改写为 "Of the next @count bankdays after @start_date, which one occurs last?"

SELECT @end_date = MAX(date)
FROM (
  SELECT TOP(@count)
    date
  FROM Calendar
  WHERE date > @start_date
    AND kindofday = 'bankday'
  ORDER BY date
) t

由于您使用的是 SQL 服务器,您可以使用 ranking 函数对非银行工作日进行排序并获得序列号,然后将其与您的天数相匹配想补充。

SELECT date
FROM (
  SELECT date AS DATE, 
   ROW_NUMBER() OVER (ORDER BY date) AS PLUS_DAYS
  FROM calendar
  WHERE date > @start_date AND KINDOFDAY <> 'bankday'
  ORDER BY date
) TEMP 
WHERE TEMP.PLUS_DAYS = @plus_days

我偶然发现了这个较旧的问题,并对使用 window 函数回答以消除嵌套查询感到好奇

SELECT DISTINCT TOP (@count)
    @end_date = MAX(date) OVER ()
FROM
    Calendar
WHERE
    date > @start_date
    AND kindofday = 'bankday'

而现实是因为 MAX(date) OVER() 对每一行都是相同的,你甚至不需要 DISTINCT

SELECT TOP (@count)
    @end_date = MAX(date) OVER ()
FROM
    Calendar
WHERE
    date > @start_date
    AND kindofday = 'bankday'

这里有一个完整的例子供您参考:

DECLARE @end_date AS DATETIME
DECLARE @start_date AS DATETIME = '12/15/2016'
DECLARE @count INT = 12

;WITH Calendar AS (
    SELECT
       CAST('12/1/2016' AS DATETIME) as date
           ,'bankday' as kindofday
    UNION ALL
    SELECT
       date + 1
       ,CASE
          WHEN date + 1 = '12/25/2016' THEN 'holiday'
          WHEN DATEPART(dw,date + 1) IN (1,7) THEN 'weekend'
          ELSE 'bankday'
       END
    FROM
       Calendar
    WHERE date + 1 <= EOMONTH(date)
)

SELECT TOP (@count)
    @end_date = MAX(date) OVER ()
FROM
    Calendar
WHERE
    date > @start_date
    AND kindofday = 'bankday'

SELECT @end_date