计算从每月16日到每月15日的小时数的存储过程

时间:2014-09-29 23:16:31

标签: sql sql-server sql-server-2008 tsql stored-procedures

我正在编写一个存储过程(对于SQL Server 2012),该存储过程应该从每个月的16-15开始计算员工的小时数。

我有以下数据库结构

My Database Structure

我已经编写了一个存储过程来计算小时数,但我想我只能得到周开始日期来过滤我的情况。存储过程返回错误的结果,因为每周开始日期并不总是第16个。

CREATE PROCEDURE [dbo].[spGetTotalHoursBetween16to15EveryMonth]
AS
BEGIN
    SET NOCOUNT ON 
    BEGIN TRY

    DECLARE @SixteenthDate datetime2(7) = DATEADD(DAY, 15, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
    DECLARE @currentDate datetime2(7) = getDate()
    DECLARE @LastSixteenthDate datetime2(7) = DATEADD(DAY, 15, DATEADD(MONTH, DATEDIFF(MONTH, 0, DATEADD(mm, DATEDIFF(mm, 0, GETDATE()) - 1, 0)), 0))

    IF(@currentDate >= @SixteenthDate)
    BEGIN
         SELECT 
             (Sum(Day1Hours) + sum(Day2Hours) + Sum(Day3Hours) +
              sum(Day4Hours) + Sum(Day5Hours) + sum(Day6Hours) + Sum(Day7Hours)) AS Total
         FROM 
             dbo.TimeSheets
         WHERE 
             WeekStartDate BETWEEN DATEADD(wk, DATEDIFF(wk, 0, @SixteenthDate), -1) AND @currentDate 
    END
    ELSE
    BEGIN
        SELECT 
            (Sum(Day1Hours) + sum(Day2Hours) + Sum(Day3Hours) + 
             sum(Day4Hours) + Sum(Day5Hours) + sum(Day6Hours) + Sum(Day7Hours)) AS Total
        FROM 
           dbo.TimeSheets
        WHERE 
           WeekStartDate BETWEEN DATEADD(wk, DATEDIFF(wk, 0, @LastSixteenthDate), -1) AND @currentDate
    END
    END TRY
    BEGIN CATCH
       THROW
    END CATCH
END

3 个答案:

答案 0 :(得分:0)

始终从开始或月末开始。

E.g。这是一些逻辑

开始日期=上个月的开始日期+16

结束日期=当月的开始日期+15

以下内容可能会帮助您确定日期

-- First Day of the month
select DATEADD(mm, DATEDIFF(mm,0,getdate()), 0)

-- Last Day of previous month
select dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate()  ), 0))

更多示例是here

答案 1 :(得分:0)

通过一点数据规范化,生活变得更容易。不要使用电子表格样式表

CREATE VIEW Timesheets_Normalized AS
SELECT 
  [id]
 ,[Date] = DATEADD(day,[Date_Offset],[WeekStartDate])
 ,[Hours]
FROM MyTable a
UNPIVOT([Hours] FOR [Date_Column] IN (Day1Hours,Day2Hours,Day3Hours,Day4Hours,Day5Hours,Day6Hours,Day7Hours)) b
INNER JOIN (VALUES (0,'Day1Hours'),(1,'Day2Hours'),(2,'Day3Hours'),(3,'Day4Hours'),(4,'Day5Hours'),(5,'Day6Hours'),(6,'Day7Hours')) c([Date_Offset],[Date_Column])
  ON (b.[Date_Column] = c.[Date_Column])

然后你可以非常简单地得到答案:

SELECT
  MIN([Date])  AS [PayrollMonthStart]
 ,MAX([Date])  AS [PayrollMonthEnd]
 ,SUM([Hours]) AS [TotalHours]
FROM Timesheets_Normalized
GROUP BY YEAR(DATEADD(day,-15,[Date])),MONTH(DATEADD(day,-15,[Date]))
HAVING CAST(GETDATE() AS date) BETWEEN MIN([Date]) AND MAX([Date])

答案 2 :(得分:0)

我可能只是这么简单:

declare @today          date = convert(date,current_timestamp)
declare @prev_month_end date = dateadd( day   , -day(@today) , @today          )
declare @period_start   date = dateadd( day   , 16           , @prev_month_end ) -- 16th of THIS month
declare @period_end     date = dateadd( month , 1            , @period_start   ) -- 16th of NEXT month

select @period_start = dateadd(month, -1 , @period_start ) ,
       @period_end   = dateadd(month, -1 , @period_end   )
where day(@today) < 16

select total_hours = coalesce(sum(t.hours),0)
from (           select id = t.id , report_date = dateadd(day,0,t.WeekStartDate) , hours = t.Day1Hours from dbo.TimeSheets t
       union all select id = t.id , report_date = dateadd(day,1,t.WeekStartDate) , hours = t.Day2Hours from dbo.TimeSheets t
       union all select id = t.id , report_date = dateadd(day,2,t.WeekStartDate) , hours = t.Day3Hours from dbo.TimeSheets t
       union all select id = t.id , report_date = dateadd(day,3,t.WeekStartDate) , hours = t.Day4Hours from dbo.TimeSheets t
       union all select id = t.id , report_date = dateadd(day,4,t.WeekStartDate) , hours = t.Day5Hours from dbo.TimeSheets t
       union all select id = t.id , report_date = dateadd(day,5,t.WeekStartDate) , hours = t.Day6Hours from dbo.TimeSheets t
       union all select id = t.id , report_date = dateadd(day,6,t.WeekStartDate) , hours = t.Day7Hours from dbo.TimeSheets t
     ) t
where t.report_date >= @period_start
  and t.report_date <  @period_end