在给定月份的工作日计数

时间:2014-07-18 23:01:31

标签: sql sql-server sql-server-2008

我遇到了如何根据包含日期的列创建计算列的问题。例如,我有一个包含从7月开始的日期的列。

需要按照使用SQL服务器的图片中所述计算DAY。

那么基本上可以根据包含大量日期的现有列创建列吗?我需要这是动态的。

WeekDay     Date        Day
---------------------------
Friday      3-Jan-14    1
Monday      6-Jan-14    2
Tuesday     7-Jan-14    3
Wednesday   8-Jan-14    4
Thursday    9-Jan-14    5
Friday      10-Jan-14   6
Monday      13-Jan-14   7
Tuesday     14-Jan-14   8
Wednesday   15-Jan-14   9
Thursday    16-Jan-14   10
Friday      17-Jan-14   11
Monday      20-Jan-14   12
Tuesday     21-Jan-14   13
Wednesday   22-Jan-14   14
Thursday    23-Jan-14   15
Friday      24-Jan-14   16
Monday      27-Jan-14   17
Tuesday     28-Jan-14   18
Wednesday   29-Jan-14   19
Thursday    30-Jan-14   20
Friday      31-Jan-14   21

3 个答案:

答案 0 :(得分:3)

对于表,DateTable,其列为Date类型Date,以下查询将按您的要求执行。

SELECT
    DATENAME(dw, Date) AS WeekDay
    ,Date
    ,ROW_NUMBER() OVER (ORDER BY Date) AS Day
FROM DateTable
WHERE DATEPART(dw, Date) NOT IN (1, 7)
ORDER BY Date

答案 1 :(得分:0)

根据标题和主题,我猜您想尝试识别每个月的工作日数。

  

示例:

     

1月1日 - 14日是星期三,因此其工作日数为1

     

6月1日至14日是星期一,所以4号工作日(4月1日至14日和5月1日至14日是周末)

此外,结果应该是已有数据的表中的派生列。

如果以上情况属实,那么这就是我的建议

  • 创建一个函数来计算两个日期之间的工作日。 (我已经将每次誓言的最后一天作为我的初始约会,但你也可以在你决定与月份的第一天一起做+1。(个人喜好真的))
  • 更改表并添加调用函数的计算列

示例查询:

IF OBJECT_ID('test') > 0
    BEGIN
        DROP TABLE test
    END;
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ufn_WordkindDayNumber]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].ufn_WordkindDayNumber
GO

CREATE FUNCTION ufn_WordkindDayNumber(@Date DATETIME)
RETURNS INT
AS
BEGIN

DECLARE @LastDayofPreviousMonth DATETIME,
@Return int

SET @LastDayofPreviousMonth = CAST(YEAR(@Date) as VARCHAR(4))+RIGHT('00'+CAST(MONTH(@Date) as VARCHAR(2)),2)+'01'
SET @LastDayofPreviousMonth = DATEADD (day, -1, CAST(@LastDayofPreviousMonth AS DATE))

-- Logic addapted from http://stackoverflow.com/questions/252519/count-work-days-between-two-dates. Credit CMS
SELECT @Return =
    CASE 
            WHEN DATENAME(dw, @Date) = 'Sunday' OR DATENAME(dw, @Date) = 'Saturday' THEN 0
            ELSE
               (DATEDIFF(dd, @LastDayofPreviousMonth, @Date))
              -(DATEDIFF(wk, @LastDayofPreviousMonth, @Date) * 2)
              -(CASE WHEN DATENAME(dw, @Date) IN ('Saturday', 'Sunday') THEN 1 ELSE 0 END)
            END

    -- Return the result of the function
    RETURN @Return
END

GO

CREATE TABLE test ([date] DATE NULL);

INSERT INTO test
SELECT '27-Dec-13' UNION ALL
SELECT '28-Dec-13' UNION ALL
SELECT '29-Dec-13'

ALTER TABLE test
ADD WordkindDayNumber AS dbo.ufn_WordkindDayNumber(Date);

GO

INSERT INTO test
SELECT '30-Dec-13' UNION ALL
SELECT '31-Dec-13' 

SELECT *
FROM test;

DROP TABLE test;

验证脚本:

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ufn_WordkindDayNumber]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].ufn_WordkindDayNumber
GO

CREATE FUNCTION ufn_WordkindDayNumber(@Date DATETIME)
RETURNS INT
AS
BEGIN

DECLARE @LastDayofPreviousMonth DATETIME,
@Return int

SET @LastDayofPreviousMonth = CAST(YEAR(@Date) as VARCHAR(4))+RIGHT('00'+CAST(MONTH(@Date) as VARCHAR(2)),2)+'01'
SET @LastDayofPreviousMonth = DATEADD (day, -1, CAST(@LastDayofPreviousMonth AS DATE))

-- Logic addapted from http://stackoverflow.com/questions/252519/count-work-days-between-two-dates. Credit CMS
SELECT @Return =
    CASE 
            WHEN DATENAME(dw, @Date) = 'Sunday' OR DATENAME(dw, @Date) = 'Saturday' THEN 0
            ELSE
               (DATEDIFF(dd, @LastDayofPreviousMonth, @Date))
              -(DATEDIFF(wk, @LastDayofPreviousMonth, @Date) * 2)
              -(CASE WHEN DATENAME(dw, @Date) IN ('Saturday', 'Sunday') THEN 1 ELSE 0 END)
            END

    -- Return the result of the function
    RETURN @Return
END

GO

;WITH cte_TestData(Date) AS
(SELECT '30-Dec-13' UNION ALL
SELECT '31-Dec-13' UNION ALL
SELECT '1-Jan-14' UNION ALL
SELECT '2-Jan-14' UNION ALL
SELECT '3-Jan-14' UNION ALL
SELECT '4-Jan-14' UNION ALL
SELECT '5-Jan-14' UNION ALL
SELECT '6-Jan-14' UNION ALL
SELECT '7-Jan-14' UNION ALL
SELECT '8-Jan-14' UNION ALL
SELECT '9-Jan-14' UNION ALL
SELECT '10-Jan-14' UNION ALL
SELECT '11-Jan-14' UNION ALL
SELECT '12-Jan-14' UNION ALL
SELECT '13-Jan-14' UNION ALL
SELECT '14-Jan-14' UNION ALL
SELECT '15-Jan-14' UNION ALL
SELECT '16-Jan-14' UNION ALL
SELECT '17-Jan-14' UNION ALL
SELECT '18-Jan-14' UNION ALL
SELECT '19-Jan-14' UNION ALL
SELECT '20-Jan-14' UNION ALL
SELECT '21-Jan-14' UNION ALL
SELECT '22-Jan-14' UNION ALL
SELECT '23-Jan-14' UNION ALL
SELECT '24-Jan-14' UNION ALL
SELECT '25-Jan-14' UNION ALL
SELECT '26-Jan-14' UNION ALL
SELECT '27-Jan-14' UNION ALL
SELECT '28-Jan-14' UNION ALL
SELECT '29-Jan-14' UNION ALL
SELECT '30-Jan-14' UNION ALL
SELECT '31-Jan-14' )
,cte_FirstDateofMonth as
(
SELECT Date, 
        CAST(YEAR(DATE) as VARCHAR(4))+RIGHT('00'+CAST(MONTH(DATE) as VARCHAR(2)),2)+'01' AS FDoM
FROM cte_TestData
)
,cte_LastDayofPreviousMonth as
(
SELECT Date, 
        DATEADD (day, -1, CAST(FDoM AS DATE)) as LDoPM
FROM cte_FirstDateofMonth
)
SELECT  [Date],
        DATENAME(dw, Date) AS DatofWeek,
        CASE 
            WHEN DATENAME(dw, Date) = 'Sunday' OR DATENAME(dw, Date) = 'Saturday' THEN 0
            ELSE
            DATEDIFF(dd, LDoPM, Date) 
            - (DATEDIFF(wk, LDoPM, Date) * 2) 
            - (CASE
                  WHEN DATENAME(dw, Date) = 'Sunday' OR DATENAME(dw, Date) = 'Saturday' THEN 1
                  ELSE 0
              END) 
        END AS WordkindDayNumber,
        dbo.ufn_WordkindDayNumber(Date) as FN_WordkindDayNumber

FROM cte_LastDayofPreviousMonth;

答案 2 :(得分:0)

I created this solution which I think is simple, because you don't need to create a table:

DECLARE @Begin DATETIME = '20160628'
DECLARE @End DATETIME = '20160802 23:59'

;WITH Cte AS
(
    SELECT
        @Begin AS 'Dia'
        ,DATEPART(WEEKDAY,@Begin) AS DiaSemana

    UNION ALL

    SELECT 
        CteADD.Dia
        ,DATEPART(WEEKDAY,CteADD.Dia) AS DiaSemana
    FROM        
        Cte
        CROSS APPLY (SELECT DATEADD(DD,1,Cte.Dia) AS Dia ) CteADD
    WHERE
        CteADD.Dia < @End   
)       

SELECT
    DiaSemana
    ,COUNT(DiaSemana) AS 'QntDias'
FROM
    Cte
GROUP BY
    DiaSemana