SQL Server 2008 专家们,大家好。
我需要在
SELECT
声明中应用以下规则来设置工人(小时工)工作日的开始和结束时间。我为我对 SQL 的无知提前道歉。
规则是,如果他们在开始时间(存储在工作人员
starttime
列中的时间)当天或之前登录,则将其开始时间设置为该工作人员的表字段中存储的值,并因此获得开始时间的积分他们的开始时间。
如果他们在存储在工作人员列中的结束时间之前或之后的 10 分钟内注销,他们将获得全天的积分,这是存储在工作人员表列中的另一个值,否则他们将受到一定百分比的处罚一个小时,即他们的注销时间四舍五入到最接近他们注销时间的 0.25 个小时。即,如果他们设置为在 4:30 注销,而他们在 4:18 注销,则他们的注销时间为 4:15。如果他们在 4:20 注销,并且设置为在 4:30 注销,则他们的注销时间为 4:30。
第一条规则适用于所有工作日时间少于或等于预期工作日值的小时工。需要注意的是,对于那些可以加班的人(位值设置为 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
这是一个处理您描述的约束的示例选择。 CTE 创建表用于测试目的。主查询显示计算结果。您已经使用过 datediffs 和 dateadds,所以没有什么神秘的。如果您以前没有使用过 %,它是 取模运算符,用于将时间四舍五入到 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 的表达式才能计算计费小时数。您不能重复使用在同一范围内定义的别名,但您可以创建派生表或视图,甚至计算字段。查看从工作流返回的列和所有其他表达式可能是最好的。
在其他查询中使用此视图可以通过将逻辑封装在一个地方来简化事情。