【问题标题】:Stored Procedure for Calculating hours from 16th of Every Month to 15 of every month每月 16 日到 15 日计算小时数的存储过程
【发布时间】:2014-09-29 23:16:30
【问题描述】:

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

我有以下数据库结构

我已经编写了一个存储过程来计算小时数,但我认为我只能获取星期开始日期来过滤我的条件。存储过程返回了错误的结果,因为每周的开始日期并不总是 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

【问题讨论】:

  • 为什么这被标记为 ASP.Net?
  • 旁注:如果你使用DATETIME2(7)(这是一个的东西!),那么你应该开始使用SYSDATETIME()而不是GETDATE()在您的“当前日期”上获得与其他任何时间相同的准确性。

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


【解决方案1】:

我可能只是用简单的方法来做:

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

【讨论】:

  • 感谢您的建议。我还需要输入日期并获取从 16 日到该日期的工资小时数。例如,如果我想知道员工从 16 日到今天的日期(输入参数)工作了多少小时,我应该能够看到。假设一名员工从 16 日开始工作,他想查看他应该能够看到的当前总小时数。谢谢
【解决方案2】:

总是从月初或月底开始。

例如这是一些逻辑

开始日期 = 上个月的开始日期 + 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

【讨论】:

    【解决方案3】:

    通过一点数据规范化,生活会更轻松。不要使用电子表格样式的表格

    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])
    

    【讨论】:

      猜你喜欢
      • 2012-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-14
      相关资源
      最近更新 更多