我可以在没有游标的SQL函数中这样做吗? [英] Can I do this in SQL function without a cursor?

查看:141
本文介绍了我可以在没有游标的SQL函数中这样做吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用时间表数据库。简单来说,TimesheetEntries表有四列

I'm working on a timesheet database. In simple terms, the TimesheetEntries table has four columns

ID int (identity, 1, 1)
StaffID int
ClockedIn datetime
ClockedOut datetime

我被要求写一份报告按日期范围显示工作人员出勤。用户输入日期,并且报告输出所有参加的工作人员的计时进出时间及其在现场的持续时间。

I've been asked to write a report to show staff attendance by date range. The user puts in a date, and the report outputs the clocking in and out times of all attending staff members together with their duration on-site.

然而,这是工作人员有时候会离开网站很短的时间,而报告要求忽略这些(当他们离开网站不到2小时)。

However, and this is where it gets tricky, staff members sometimes clock out to leave the site for short periods, and the report is required to ignore these (when they leave the site for less than 2 hours).

所以,让我们假设以下条目:

So, let's assume the following entries

ID  StaffID  ClockedIn    ClockedOut
1   4        0900         1200
2   4        1330         1730
3   5        0900         1200
4   5        1409         1730
5   4        1830         1930

报表的输出应该

StaffID  ClockedIn    ClockedOut
4        0900         1930
5        0900         1200     
5        1409         1730  

这样做没有光标,甚至光标嵌套在光标(这是我现在在哪里!)?我们不是在这里谈论庞大的数据集,性能并不是真正的问题(它是一个报告,而不是一个生产系统),但我真的不喜欢光标,如果我可以避免它们。

Is there any way of doing this without a cursor or even a cursor nested inside a cursor (which is where I'm at right now!)? We're not talking about huge datasets here and performance isn't really an issue (it's a report, not a production system) but I really don't like cursors if I can avoid them.

感谢

爱德华

推荐答案

来自Jeremy的回答以上的数据,但在问题上有一个完全不同的方式。这使用递归CTE,我认为需要SQL Server 2005.它报告结果准确(我相信),还报告记录在时间段内的时钟数和总分钟数(可以超过120,因为限制是每个非现场时段少于两个小时)。

I used the data from Jeremy's response above but went at the problem a whole different way. This uses a recursive CTE, which I think requires SQL Server 2005. It reports the results accurately (I believe) and also reports the number of clock-ins recorded during the timeframe and the total number of minutes off (can be more than 120 because the restriction is simply that each offsite period is less than two hours).

declare @TimeSheetEntries table 
    ( 
    ID int identity not null primary key, 
    StaffID int not null, 
    ClockedIn datetime not null, 
    ClockedOut datetime not null 
    ); 

insert into @TimeSheetEntries 
    ( 
    StaffID, 
    ClockedIn, 
    ClockedOut 
    ) 
select 
    4, 
    '2012-01-01 09:00:00', 
    '2012-01-01 12:00:00' 
union all select 
    4, 
    '2012-01-01 13:30:00', 
    '2012-01-01 17:30:00' 
union all select 
    5, 
    '2012-01-01 09:00:00', 
    '2012-01-01 12:00:00' 
union all select 
    5, 
    '2012-01-01 14:09:00', 
    '2012-01-01 17:30:00'
union all select
    4,
    '2012-01-01 18:30:00', 
    '2012-01-01 19:30:00';


WITH ClockData AS
(
    SELECT ID, StaffID, ClockedIn, ClockedOut AS EffectiveClockout, 1 AS NumClockIns, 0 AS MinutesOff
    FROM @TimeSheetEntries ts
    WHERE NOT EXISTS (SELECT ID FROM @TimeSheetEntries tsWhere WHERE tsWhere.ClockedOut BETWEEN DATEADD(hour, -2, ts.ClockedIn) AND ts.ClockedIn)

    UNION ALL

    SELECT cd.ID, cd.StaffID, cd.ClockedIn, ts.ClockedOut AS EffectiveClockout, cd.NumClockIns + 1 AS NumClockIns, cd.MinutesOff + DateDiff(minute, cd.EffectiveClockout, ts.ClockedIn) AS MinutesOff
    FROM @TimeSheetEntries ts
    INNER JOIN ClockData cd
        ON ts.StaffID = cd.StaffID
            AND ts.ClockedIn BETWEEN cd.EffectiveClockout AND dateadd(hour, 2, cd.EffectiveClockout)
)
SELECT *
FROM ClockData cd
WHERE NumClockIns = (SELECT MAX(NumClockIns) FROM ClockData WHERE ID = cd.ID)

这会返回:

ID   StaffID   ClockedIn                 EffectiveClockout        NumClockIns   MinutesOff
3    5         2012-01-01 09:00:00.000   2012-01-01 12:00:00.000  1             0
4    5         2012-01-01 14:09:00.000   2012-01-01 17:30:00.000  1             0
1    4         2012-01-01 09:00:00.000   2012-01-01 19:30:00.000  3             150

UPDATE

如果不清楚,MinutesOff 允许时间,或者在同一行中显示的ClockedIn和EffectiveClockout之间吃掉的时间量。因此,StaffID 5在钟表时段之间关闭了129分钟,但没有余额时间,因此MinutesOff对于这两行都为0。

In case it isn't clear, the MinutesOff is only the 'allowance' time, or the amount of time 'eaten' between the ClockedIn and EffectiveClockout shown in the same row. So, StaffID 5 took 129 minutes off between clocked time periods, but no allowance time, so MinutesOff is 0 for both rows.

这篇关于我可以在没有游标的SQL函数中这样做吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆