【问题标题】:SQL query to calculate days worked per Month用于计算每月工作天数的 SQL 查询
【发布时间】:2013-07-25 07:43:51
【问题描述】:

我卡在 SQL 查询上。我正在使用 SQL Server。

给定一个表,其中包含具有开始和结束日期的作业。这些工作可能跨越数天或数月。我需要获取与这些月份相交的所有工作每个月的总工作天数。

工作

-----------------------------------
JobId | Start  | End    | DayRate |
-----------------------------------
1     | 1.1.13 | 2.2.13 | 2500    |
2     | 5.1.13 | 5.2.13 | 2000    |
3     | 3.3.13 | 2.4.13 | 3000    |

我需要的结果是:

Month | Days
--------------
Jan   | 57
Feb   | 7
Mar   | 28
Apr   | 2

知道我将如何纠正这样的查询吗?

我还想根据每个工作的天数乘以天数来计算每个月的总和,我将如何将其添加到结果中?

谢谢

【问题讨论】:

  • 一个周期中的所有天都在工作还是可以有假期?
  • 整天都在工作,不需要考虑假期。

标签: sql sql-server tsql


【解决方案1】:

您可以使用递归 CTE 提取每个 JobID 从头到尾的所有日期,然后按月(我猜是年份)分组。

;WITH CTE_TotalDays AS 
(
    SELECT [Start] AS DT, JobID FROM dbo.Jobs
    UNION ALL
    SELECT DATEADD(DD,1,c.DT), c.JobID FROM CTE_TotalDays c
    WHERE  c.DT < (SELECT [End] FROM Jobs j2 WHERE j2.JobId  = c.JobID)
)
SELECT 
     MONTH(DT) AS [Month] 
    ,YEAR(DT) AS [Year]
    ,COUNT(*) AS [Days] 
FROM CTE_TotalDays
GROUP BY MONTH(DT),YEAR(DT)
OPTION (MAXRECURSION 0)

SQLFiddle DEMO

PS:在您的示例中,一月有 58 天,而不是 57 天;)

【讨论】:

  • 当我对我的数据运行它时出现错误:在语句完成之前,最大递归 100 已用完。
  • @JCoder23,哦,100 是 CTE 的默认最大递归(以防止无限循环)。您可以通过在查询末尾添加 OPTION (MAXRECURSION n) 来设置自己的值 - 0 表示无限。查询和演示已更新。
  • 您的解决方案运行良好!我还想根据将日工资乘以每个工作的工作天数来计算每个月的总和,我将如何将其添加到结果中?谢谢
  • @JCoder23 或者您可以在 CTE 之后进行添加步骤,您也可以在其中按 JobID 分组,然后加入您的表格以获取费率 - sqlfiddle.com/#!6/9d009/7
【解决方案2】:

您可以使用以下方法:

/* Your table with periods */
declare @table table(JobId int, Start date, [End] date, DayRate money)

INSERT INTO @table (JobId , Start, [End], DayRate)
VALUES
(1, '20130101','20130202', 2500),
(2,'20130105','20130205', 2000),
(3,'20130303','20130402' , 3000 )

/* create table where stored all possible dates
   if this code are supposed to be executed often you can create 
   table with dates ones to avoid overhead of filling it */
declare @dates table(d date)

declare @d date='20000101'
WHILE @d<'20500101'
    BEGIN 
        INSERT INTO @dates (d) VALUES (@d)
        SET @d=DATEADD(DAY,1,@d)
    END;

/* and at last get desired output */

SELECT YEAR(d.d) [YEAR], DATENAME(month,d.d) [MONTH], COUNT(*) [Days]
FROM @dates d
     CROSS JOIN @table t
WHERE d.d BETWEEN t.Start AND t.[End]
GROUP BY YEAR(d.d), DATENAME(month,d.d)

【讨论】:

    【解决方案3】:

    这只有 1 个递归调用,而不是每行 1 个。我想当您拥有大量数据时,这将比选择的答案表现更好。

    declare @t table(JobId int, Start date, [End] date, DayRate int)
    insert @t values
    (1,'2013-01-01','2013-02-02', 2500),(2,'2013-01-05','2013-02-05', 2000),(3,'2013-03-03', '2013-04-02',3000)
    
    ;WITH a AS 
    (
    
    SELECT min(Start) s, max([End]) e
    FROM @t
    ), b AS
    (
    SELECT s, e from a
    UNION ALL
    SELECT dateadd(day, 1, s), e
    FROM b WHERE s <> e
    )
    SELECT 
         MONTH(b.s) AS [Month] 
        ,YEAR(b.s) AS [Year]
        ,COUNT(*) AS [Days]
        ,SUM(DayRate) MonthDayRate
    FROM b
    join @t t
    on b.s between t.Start and t.[End]
    GROUP BY MONTH(b.s),YEAR(b.s)
    OPTION (MAXRECURSION 0)
    

    结果:

    Month   Year    Days    MonthDayRate
    1       2013    58      131500
    2       2013    7       15000
    3       2013    29      87000
    4       2013    2       6000
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多