【问题标题】:SQL Server 2008 CASE Logic in SELECT statementSELECT 语句中的 SQL Server 2008 CASE 逻辑
【发布时间】:2012-04-02 18:34:48
【问题描述】:

再次问候 SQL Server 2008 大师。

我需要在SELECT 语句中将以下规则应用于设置工人工作日(小时工)的开始和结束时间。我提前为我对 SQL 的无知表示歉意。

  1. 规则是将他们的开始时间设置为存储在该工作人员的表字段中的值,如果他们在开始时间或之前登录(存储在工作人员starttime 列中的时间)并因此获得启动的信用在他们的开始时间。

    如果他们在结束时间之前或之后的 10 分钟内注销,则存储在工人的列中,他们将获得全天的信用,另一个值存储在工人表的列中,否则将受到处罚一个小时的某个百分比,即他们的注销时间四舍五入到最接近他们注销时间的 0.25 小时。即,如果他们设置为在 4:30 注销,并且他们在 4:18 注销,则他们的注销时间为 4:15。如果他们在 4:20 注销,并设置在 4:30 注销,则他们的注销时间为 4:30。

  2. 第一条规则适用于其工作日时间少于或等于其预期工作日值的所有小时工。需要注意的是,对于那些可以加班的人(位值设置为 1)。如果允许加班,计费小时数可能会超过为他们存储的全天值,因此他们的注销 - 登录时间值可能会超过其全天值。

    问题是,这些规则是否可以在 SELECT 语句中计算出来,如果可以,我可以得到一些代码方面的帮助吗?

包含信息的列是:

    worker.startime (TIME)
    worker.endtime  (TIME)
    worker.overtimeallowed (BIT)
    worker.workdayhours (decimal (12,2))
    worker.penaltyvalue (decimal (12,2))

如果它需要 UDF 或存储过程(因为我使用的是 Telerik ReportViewer),我不确定它是否会被支持,但这可能是另一个问题。

到目前为止,我在应用一些 CASE 逻辑方面获得了一些帮助 - 计算工人是否获得了 1/2 午餐的功劳。提供的代码按承诺工作。我相信这可能是对该逻辑的扩展 - 所以我将在此处提供我的代码:

      -- for testing purposes only.
      DECLARE @StartDate AS DateTime
      SET @StartDate = CAST('03/25/2012' AS DATE)
      DECLARE @EndDate AS DateTime
      SET @EndDate = CAST('04/10/2012' AS DATE)

      SELECT 
      w.Firstname 
     ,w.Lastname 
     ,wf.Login
     ,wf.logout
     ,ROUND(CAST(DATEDIFF(MI, wf.Login, wf.Logout) AS DECIMAL)/60,2) 
     - CASE 
        WHEN DATEDIFF(hour, wf.Login, wf.Logout) < w.MinimumHours THEN      
          w.LunchDeduction
        ELSE
        0
       END AS [Hours Credited]
     FROM Workers AS w 
     JOIN Workflow AS wf 
     ON wf.LoggedInWorkerid = w.ID 
     JOIN Roles AS r
     ON w.RoleID = r.RoleID
     WHERE (r.Descript = 'Hourly')
     AND wf.Login >= @StartDate AND wf.Logout <= @EndDate 
     ORDER BY w.Lastname, w.Firstname

【问题讨论】:

  • 是的,听起来这一切都可以在查询中完成。像大多数问题一样,尝试将其分解。剪切并粘贴您现有的CASE 并对其进行修改以检查“10 分钟”规则并输出一个标志。然后继续一次添加一层。你很快就会得到它。
  • 在大多数司法管辖区,如果员工提早打卡,即使加班未获批准,您也必须支付他们的时间。他们工作,他们得到报酬。时期。是的,这是一个问题,但不是你通过扣留工资来处理的问题。 HR 与经理讨论设定期望,经理与员工讨论他们何时出现和打卡;如果仍然没有达到预期,管理层就会开始使用纪律程序来强制执行。但如果他们打卡上班,他们就会得到报酬。

标签: sql-server-2008 case field


【解决方案1】:

这是一个处理您描述的约束的示例选择。 CTE 为测试目的创建表。主查询显示计算。您已经使用过 datediffs 和 dateadds,所以没有任何谜团。如果你之前没有使用过 %,那是 modulo operator 用来将时间四舍五入到 15 分钟。

;with worker (ID, overtime, startTime, endTime) as
(
    select 1, 1, CAST ('08:30' as time), CAST ('16:30' as time)
    union all
    select 2, 0, CAST ('08:30' as time), CAST ('16:30' as time)
    union all
    select 3, 0, CAST ('08:30' as time), CAST ('16:30' as time)
),
-- Test table of workflows
wf (workerID, login, logout) as
(
    select 1, CAST ('2012-03-11 08:20' as datetime), CAST ('2012-03-11 19:33' as datetime)
    union all
    select 2, CAST ('2012-03-11 08:50' as datetime), CAST ('2012-03-11 16:20' as datetime)
    union all
    select 3, CAST ('2012-03-11 08:22' as datetime), CAST ('2012-03-11 16:18' as datetime)
)
select wf.workerID,
  wf.login,
  wf.logout,
  --  if starttime > login return startTime else login
  case when DATEDIFF(MI, w.startTime, cast (wf.login as time)) < 0 
    then cast(CAST (wf.login AS date) AS datetime) + w.startTime
    else wf.login
  end roundedLogin,
  case when w.overtime = 1 -- Round to 15 minutes whenever finished
         OR
         -- Round to 15 minutes if left ten or more minutes before endTime
            DATEDIFF(MI, cast (wf.logout as time), dateadd (MI, -10, w.endTime)) > 0 
    then dateadd (MI, -(DATEPART (MI, wf.logout) % 15), wf.logout)
    -- stop at endTime if overtime = 0 OR left job at apropriate time
    else cast(CAST (wf.logout AS date) AS datetime) + w.endTime
  end roundedLogout
from worker w 
  inner join wf 
     on w.ID = wf.workerID

这种方法会有问题。当您开始将数学集成到原始查询中时,您会注意到您必须再次编写计算 roundedLogin 和 roundedLogout 的表达式来计算计费小时数。您不能重用在同一范围内定义的别名,但您可以创建派生表或视图甚至计算字段。查看来自工作流和所有其他表达式的返回列可能是最好的。

在其他查询中使用此视图将通过在一个地方封装逻辑来简化事情。

【讨论】:

  • 我喜欢尼古拉的这个答案。我已经整理了一个存储过程,但它没有这个逻辑。我似乎无法输入我与您拼凑的代码,所以我想我必须问另一个问题。借助报告背后存储过程的强大功能 - 我假设我可以在 roundedLogin 和 roundedLogout 上获得 DATEDIFF,这将是非常棒的。
  • 是的,您可以,但目前您每次使用它时都必须重复表达式,即使在同一个查询中也是如此。因此,建议创建一个添加这两列的工作流视图。
  • 我玩这个已经有一段时间了,现在想弄清楚。为什么 wf.logout 的值 2012-03-05 19:20:45.000 在 roundLogout 中设置为 1900-01-01 16:30:00.000 使用你的 -->CASE WHEN w.OvertimeOk = 1 OR DATEDIFF(MI, wf .logout, dateadd (MI, 10, w.endTime)) > 0 THEN dateadd (MI, -(DATEPART (MI, wf.logout) % 15), wf.logout)
  • 每当进行比较时,wf.login 和 wf.logout 都应该只截断为时间。我要编辑我的示例。
  • @CliffRobinson 我很仓促,完全忽略了登录和注销字段中的日期部分。立即尝试。
猜你喜欢
  • 2010-11-10
  • 2013-12-06
  • 1970-01-01
  • 1970-01-01
  • 2012-05-18
  • 2016-12-18
  • 2014-08-29
  • 2013-04-07
相关资源
最近更新 更多