Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何为特定员工安排所有进出时间?_Sql_Sql Server - Fatal编程技术网

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 by
id 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个小时?)