从给定日期开始的工作日

时间:2014-07-16 07:52:57

标签: sql sql-server tsql

用户将选择前端和灵活日期的日期,例如,如果他们选择'2014-07-17'作为日期,灵活日期为2,那么我们需要显示前2个和下2个工作日,如下所示,

  1. 2014年7月15日
  2. 2014年7月16日
  3. 2014年7月17日
  4. 2014年7月20日
  5. 2014年7月21日
  6. 不包括周末(周五和周六),周末是星期五和星期六。

    我使用了以下查询

    DECLARE @MinDate DATE, @MaxDate DATE;
        SELECT @MinDate = DATEADD(Day, -@inyDays ,@dtDate), @MaxDate = DATEADD(Day,@inyDays ,@dtDate)
    
        DECLARE @DayExclusionValue VARCHAR(20)
        SELECT @DayExclusionValue = dbo.UDF_GetConfigSettingValue('DaysToExclude')
    
        DECLARE @NumOfWeekends INT
        SELECT @NumOfWeekends= (DATEDIFF(wk, @MinDate, @MaxDate) * 2) +(CASE WHEN DATENAME(dw, @MinDate) = 'Friday' THEN 1 ELSE 0 END)      +(CASE WHEN DATENAME(dw, @MaxDate) = 'Saturday' THEN 1 ELSE 0 END)
    
        SET @MaxDate = DATEADD(Day,@inyDays + @NumOfWeekends ,@dtDate)
    
        ;WITH CalculatedDates AS
        (
            SELECT dates = @MinDate
            UNION ALL
            SELECT DATEADD(day, 1, dates)
            FROM CalculatedDates
            WHERE DATEADD(day, 1, dates)  <= @MaxDate
    
        )
        SELECT dates FROM CalculatedDates 
        WHERE dates >= CAST(GETDATE() AS DATE)
        AND DATENAME(DW, dates) NOT IN (SELECT Value FROM UDF_GetTableFromString(@DayExclusionValue))
        OPTION (MAXRECURSION 0);
    

    但上述查询无效。

    你能不能给我建议任何其他解决方案。

2 个答案:

答案 0 :(得分:0)

此示例适用于Oracle,您没有说明您使用的是什么数据库。如果您有假期列表,您需要按照指示加入。它需要是一个外连接,你需要添加一个案例或某些东西,以便度假表排除&#39;天覆盖生成的天数。

我也随机选择了乘数。当只处理周末8时绰绰有余,但如果你的假期表包括很多连续的休假日,它可能不再是。

select d from(
select rownum nn, d, sysdate - d, first_value (rownum) over (order by abs(sysdate-d)) zero_valu
from (
select sysdate+n d, to_char(sysdate+n,'DAY'), CASE to_char(sysdate+n,'D') WHEN '6' THEN 'exclude' WHEN '7' THEN 'exclude' ELSE 'include' END e_or_i  from
(SELECT ROWNUM-9 n -- 9=flexibleday*8/2 +1
FROM   ( SELECT 1 just_a_column
         FROM   dual
         CONNECT BY LEVEL <= 16 -- 8=flexibleday * 8
       ) 
)
) where e_or_i = 'include'  -- in this step you need to join in a table of holidays or such if you need that.
) where abs(nn-7) <= 2 -- 2=flexiday
order by d

答案 1 :(得分:0)

DECLARE @StartDate DATE = '2014-07-17';

SELECT *
FROM
(
    --Show Closest Previous 2 Days Not In Friday or Saturday
    SELECT TOP 2
        DATEADD(DAY, -nr, @StartDate) CheckDate, 
        DATENAME(DW, DATEADD(DAY, -nr, @StartDate)) CheckName, 
        -nr CheckCount
    FROM (VALUES(1),(2),(3),(4)) AS Numbers(nr)
    WHERE DATENAME(DW, DATEADD(DAY, -nr, @StartDate)) NOT IN ('Friday','Saturday')

    UNION ALL

    --Show Todays Date If Not Friday or Saturday
    SELECT TOP 1
        DATEADD(DAY, +nr, @StartDate) CheckDate, 
        DATENAME(DW, DATEADD(DAY, +nr, @StartDate)) CheckName, 
        nr CheckCount
    FROM (VALUES(0)) AS Numbers(nr)
    WHERE DATENAME(DW, DATEADD(DAY, +nr, @StartDate)) NOT IN ('Friday','Saturday')

    UNION ALL

    --Show Closest Next 2 Days Not In Friday or Saturday
    SELECT TOP 2
        DATEADD(DAY, +nr, @StartDate) CheckDate, 
        DATENAME(DW, DATEADD(DAY, +nr, @StartDate)) CheckName, 
        nr CheckCount
    FROM (VALUES(1),(2),(3),(4)) AS Numbers(nr)
    WHERE DATENAME(DW, DATEADD(DAY, +nr, @StartDate)) NOT IN ('Friday','Saturday')
) d
ORDER BY d.CheckDate

我将其分为3个部分,前2天,今天(如果适用)和接下来的2天 这是输出:

CheckDate   CheckName  CheckCount
2014-07-15  Tuesday    -2
2014-07-16  Wednesday  -1
2014-07-17  Thursday   0
2014-07-20  Sunday     3
2014-07-21  Monday     4

我使用日期名称,因为不确定服务器设置为@@ datefirst的是什么。 values()部分只是一个数字表(您应该创建一个数字表,与您想要返回的记录数量以及您要越过的任何周末一样大)然后将替换第一部分和最后部分中的TOP 2以及您希望在之前和之后返回的天数。


****添加了通用数字表功能的更新:


我们在此声明我们想要提取的开始日期和上一天和下一天的数量:

DECLARE @StartDate DATE = '2014-07-20';
DECLARE @MaxBusDays INT = 5

下一节创建一个数字表(可以通过谷歌轻松找到)

DECLARE @number_of_numbers INT = 100000;
;WITH
    a AS (SELECT 1 AS i UNION ALL SELECT 1),
    b AS (SELECT 1 AS i FROM a AS x, a AS y),
    c AS (SELECT 1 AS i FROM b AS x, b AS y),
    d AS (SELECT 1 AS i FROM c AS x, c AS y),
    e AS (SELECT 1 AS i FROM d AS x, d AS y),
    f AS (SELECT 1 AS i FROM e AS x, e AS y),
    numbers AS 
(
    SELECT TOP(@number_of_numbers)
    ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS number
    FROM f
)

现在我们使用数字表和row_number设置来仅提取工作日之前和之后的行数(加上所需的日期,如果它不是fri / sat)(不是fri / sat)

SELECT *
FROM
(
    --Show Closest Previous x Working Days (Not Friday or Saturday)
    SELECT * FROM
    (
        SELECT
            DATEADD(DAY, -number, @StartDate) CheckDate, 
            DATENAME(DW, DATEADD(DAY, -number, @StartDate)) CheckName, 
            -number CheckCount,
          ROW_NUMBER() OVER (ORDER BY number ASC) AS RowCounter
        FROM Numbers
        WHERE DATENAME(DW, DATEADD(DAY, -number, @StartDate)) NOT IN ('Friday','Saturday')
    ) a
    WHERE a.RowCounter <= @MaxBusDays

    UNION ALL

    --Show Todays Date If Working Day (Not Friday or Saturday)
    SELECT TOP 1
        @StartDate CheckDate, 
        DATENAME(DW, @StartDate) CheckName, 
        0 CheckCount,
      0 RowCounter
    WHERE DATENAME(DW, @StartDate) NOT IN ('Friday','Saturday')

    UNION ALL

    --Show Closest Next x Working Days (Not Friday or Saturday)
    SELECT * FROM
    (
        SELECT
            DATEADD(DAY, +number, @StartDate) CheckDate, 
            DATENAME(DW, DATEADD(DAY, +number, @StartDate)) CheckName, 
            number CheckCount,
          ROW_NUMBER() OVER (ORDER BY number ASC) AS RowCounter
        FROM Numbers
        WHERE DATENAME(DW, DATEADD(DAY, +number, @StartDate)) NOT IN ('Friday','Saturday')
    ) b
    WHERE b.RowCounter <= @MaxBusDays

) c
ORDER BY c.CheckDate

以下是输出:(2014-07-20是中间行)

CheckDate     CheckName   CheckCount  RowCounter
2014-07-13    Sunday      -7          5
2014-07-14    Monday      -6          4
2014-07-15    Tuesday     -5          3
2014-07-16    Wednesday   -4          2
2014-07-17    Thursday    -3          1
2014-07-20    Sunday      0           0
2014-07-21    Monday      1           1
2014-07-22    Tuesday     2           2
2014-07-23    Wednesday   3           3
2014-07-24    Thursday    4           4
2014-07-27    Sunday      7           5