Sql 如何为特定员工安排所有进出时间?
我的表格如下:Sql 如何为特定员工安排所有进出时间?,sql,sql-server,Sql,Sql Server,我的表格如下: id time_stamp Access Type 1001 2017-09-05 09:35:00 IN 1002 2017-09-05 11:00:00 IN 1001 2017-09-05 12:00:00 OUT 1002 2017-09-05 12:25:00 OUT 1001 2017-09-05 13:00:00
id time_stamp Access Type
1001 2017-09-05 09:35:00 IN
1002 2017-09-05 11:00:00 IN
1001 2017-09-05 12:00:00 OUT
1002 2017-09-05 12:25:00 OUT
1001 2017-09-05 13:00:00 IN
1002 2017-09-05 14:00:00 IN
1001 2017-09-05 17:00:00 OUT
1002 2017-09-05 18:00:00 OUT
我尝试了以下查询:
SELECT ROW_NUMBER() OVER (
ORDER BY A.emp_reader_id ASC
) AS SNo
,B.emp_code
,B.emp_name
,CASE
WHEN F.event_entry_name = 'IN'
THEN A.DT
END AS in_time
,CASE
WHEN F.event_entry_name = 'OUT'
THEN A.DT
END AS out_time
,cast(left(CONVERT(TIME, a.DT), 5) AS VARCHAR) AS 'time'
,isnull(B.areaname, 'OAE6080036073000006') AS areaname
,C.dept_name
,b.emp_reader_id
,isnull(c.dept_name, '') AS group_name
,CONVERT(CHAR(11), '2017/12/30', 103) AS StartDate
,CONVERT(CHAR(11), '2018/01/11', 103) AS ToDate
,0 AS emp_card_no
FROM dbo.trnevents AS A
LEFT OUTER JOIN dbo.employee AS B ON A.emp_reader_id = B.emp_reader_id
LEFT OUTER JOIN dbo.departments AS C ON B.dept_id = C.dept_id
LEFT OUTER JOIN dbo.DevicePersonnelarea AS E ON A.POINTID = E.areaid
LEFT OUTER JOIN dbo.Event_entry AS F ON A.EVENTID = F.event_entry_id
ORDER BY A.emp_reader_id ASC
它工作,但它需要像下面这样。有时有相同的事件内和事件外:
SNo emp_code emp_name in_time out_time time areaname dept_name emp_reader_id group_name StartDate ToDate emp_card_no
1 102 Ihsan Titi NULL 2017-12-30 12:16:26.000 12:16 Dubai Sales 102 Sales 2017/12/30 2018/01/11 0
2 102 Ihsan Titi NULL 2017-12-30 12:16:27.000 12:16 Dubai Sales 102 Sales 2017/12/30 2018/01/11 0
3 102 Ihsan Titi 2017-12-30 12:44:26.000 NULL 12:44 Dubai Sales 102 Sales 2017/12/30 2018/01/11 0
4 102 Ihsan Titi 2017-12-30 16:27:48.000 NULL 16:27 Dubai Sales 102 Sales 2017/12/30 2018/01/11 0
预期输出:
SNo emp_code emp_name in_time out_time time areaname dept_name emp_reader_id group_name StartDate ToDate emp_card_no
1 102 Ihsan Titi 2017-12-30 12:16:26.000 2017-12-30 12:44:26.000 12:16 Dubai Sales 102 Sales 2017/12/30 2018/01/11 0
2 102 Ihsan Titi 2017-12-30 12:50:26.000 2017-12-30 16:27:48.000 12:16 Dubai Sales 102 Sales 2017/12/30 2018/01/11 0
请帮帮我,我就这样呆在这里了。你可以使用
支点
select id, [in], out
from
( select
id, time_stamp, accessType,
(ROW_NUMBER() over (partition by id order by time_stamp) -1 )/ 2 rn
from yourtable ) src
pivot
(min(time_stamp) for accessType in ([in],[out])) p
这假设每个“in”后面都有一个“out”,并使用行数对这些时间对进行分组。下面我处理它的方式是,如果一个事件与之前的事件类型相同,则将其视为“rogue” 流氓总是独坐,从不与任何其他事件配对 所有其他事件将配对,以便
IN
是第一项,OUT
是第二项
然后我可以把所有的东西分组,把成对的东西减少到一行
WITH
rogue_check
AS
(
SELECT
CASE WHEN LAG(F.event_entry_name) OVER (PARTITION BY A.emp_reader_number ORDER BY A.DT) = F.event_entry_name THEN 1 ELSE 0 END AS is_rogue,
*
FROM
trnevents AS A
LEFT JOIN
EVent_entry AS F
ON F.event_entry_id = A.event_id
),
sorted AS
(
SELECT
ROW_NUMBER() OVER ( ORDER BY DT) AS event_sequence_id,
ROW_NUMBER() OVER (PARTITION BY emp_reader_number, is_rogue ORDER BY DT) AS employee_checked_event_sequence_id,
*
FROM
rogue_check
)
SELECT
MIN(event_sequence_id) AS unique_id,
emp_reader_number,
MAX(CASE WHEN event_entry_name = 'IN' THEN DT END) AS time_in,
MAX(CASE WHEN event_entry_name = 'OUT' THEN DT END) AS time_out
FROM
sorted
GROUP BY
emp_reader_number,
is_rogue,
employee_checked_event_sequence_id - CASE WHEN is_rogue = 1 OR event_entry_name = 'IN' THEN 0 ELSE 1 END
ORDER BY
emp_reader_number,
unique_id
;
模式示例:
CREATE TABLE trnevents (
emp_reader_number INT,
DT DATETIME,
event_id INT
);
CREATE TABLE Event_entry (
event_entry_id INT,
event_entry_name NVARCHAR(32)
);
示例数据:
INSERT INTO Event_entry VALUES (0, N'IN'), (1, N'OUT');
INSERT INTO trnevents VALUES
(1, '2017-01-01 08:00', 0),
(1, '2017-01-01 08:01', 0),
(1, '2017-01-01 12:00', 1),
(1, '2017-01-01 13:00', 0),
(1, '2017-01-01 17:00', 1),
(1, '2017-01-01 17:01', 1)
;
示例结果:
unique_id emp_reader_number time_in time_out
1 1 01/01/2017 08:00:00 01/01/2017 12:00:00
2 1 01/01/2017 08:01:00 null
4 1 01/01/2017 13:00:00 01/01/2017 17:00:00
6 1 null 01/01/2017 17:01:00
groupby
结果比我在火车上预期的要复杂一些,因此可能会在大型数据集的执行计划中造成昂贵的排序。我很快还会考虑另一种选择
下面是一个演示,其中包含一些简单的虚拟数据,证明它至少适用于这些情况。(如果出现任何问题,请随时使用其他案例进行更新)
您可以使用以下功能:
select A_In.emp_reader_id as empId,A_In.Belongs_to,A_In.DeviceSerialNumber,
DT as EntryTime,
(
select min(DT) as OutTime
from trnevents A_Out
where EVENTID like 'IN'
and A_Out.emp_reader_id = A_In.emp_reader_id
and A_Out.DT > A_In.DT and DATEDIFF(day,A_In.Dt,A_Out.DT)=0
) as ExitTime from trnevents A_In where EVENTID like 'OUT'
from trnevents A_In
尝试使用order byid time\U stamp
将所有访问类型与OUT
相同,然后加入。将查询包装在派生表中,然后根据其结果分组。您的数据有多干净?你能保证每个IN都有一个对应的OUT吗?反之亦然?根据我的经验,这不太可能,所以如果有额外的输入或输出记录,您希望如何处理它们?(丢弃它们?假设有一定的工作时间?或者,更好的做法是,不要在计算中使用它们,但要有额外的字段来报告有多少?)这被称为“缺口和孤岛”分析——时间和出勤系统中的标准费雷。请注意,根据数据的质量和对工作模式的假设,问题可能会变得很难解决。结果将与我前面提到的相同无emp_reader_id 1 0 1 102 2017-12-30 12:16:26.000 NULL 2 1022017-12-30 12:16:27.000零3102零2017-12-30 12:44:26。000@TimeAttendanceSystem不,不会的。我只是使用了上面提到的代码,完全相同,也尝试添加行数,但结果会相同。我提到了。我用我的示例数据来回答这个问题,这说明了这个答案的一些问题,因为OP指出,输入和输出不是完全成对的。(这个答案是随附演示中的最后一个面板):它可能是隐式的,但具体来说,它还假设每个out
前面都有一个in
。(如果第一条记录是一个输出
,那么计算(rowid-1)/2
会给出不希望的结果。)@BorislavAymaliev-请表现出一些礼貌和谦逊。我对您的答案进行了评论,强调了两个您没有发现的单独语法错误,这使您能够纠正它们。我还评论了您的结果和描述之间的差异,因为我从OPs帖子和评论中了解到了这一点。根据OP所说的,输入
记录没有清晰地映射到输出
记录(某段时间我得到了相同的时间打孔输入/输出
)。你给出的答案超出了计算范围(如果我在下午1点和2点登录,下午3点退出,你说我工作了3个小时?)