再次请教SQL Server 2008大师。
我需要在SELECT
声明中将以下规则应用于工作日(每小时员工)的工人开始和结束时间的设置。我为SQL无知而提前道歉。
规则是将其开始时间设置为存储在该工作人员的表字段中的值,如果他们在开始时间或之前登录(存储在工作人员starttime
列中的时间)并且因此从他们的开始时间开始获得信誉。
如果他们在结束时间之前或之后的任何时间,如果他们在工作人员的列中存储了他们的结束时间,那么他们将获得一整天的信用,另一个值存储在工作人员表的列中,否则他们将受到处罚一小时的一些百分比,即他们的退出时间四舍五入到最接近他们退出时间的.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
答案 0 :(得分:0)
以下是处理您描述的约束的示例选择。 CTE创建用于测试目的的表。主查询显示计算。你已经与约会和日期改编工作,所以没有错误。如果您之前没有使用%,则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以计算可计费小时数。您不能重用在同一范围内定义的别名,但您可以创建派生表或视图甚至计算字段。从工作流和所有其他表达式查看返回列可能是最好的。
在其他查询中使用此视图可以通过将逻辑封装在一个位置来简化操作。