0

我有一张桌子:

CREATE TABLE timeclock(
     employeeid INT
     , logdate DATE
     , logtime TIME
     , timetype VARCHAR(1)
);

INSERT INTO test VALUES
(1, '2013-01-01', '07:00', 'I'),
(1, '2013-01-01', '07:01', 'I'),
(1, '2013-01-01', '16:00', 'O'),
(1, '2013-01-01', '16:01', 'O'),
(2, '2013-01-01', '07:00', 'I'),
(2, '2013-01-01', '16:00', 'O'),
(1, '2013-01-02', '07:00', 'I'),
(1, '2013-01-02', '16:30', 'O'),
(2, '2013-01-02', '06:30', 'I'),
(2, '2013-01-02', '15:30', 'O'),
(2, '2013-01-02', '16:30', 'I'),
(2, '2013-01-02', '23:30', 'O'),
(3, '2013-01-01', '06:30', 'I'),
(3, '2013-01-02', '16:30', 'O'),
(4, '2013-01-01', '20:30', 'I'),
(4, '2013-01-02', '05:30', 'O'),
(5, '2013-01-01', '20:30', 'O'),
(5, '2013-01-02', '05:30', 'I');

我需要获取每个员工的进出时间,忽略重复条目并识别孤立条目(没有匹配的 IN 或 OUT),以便我可以将其放在单独的列表中以通知丢失条目。

到目前为止,我有这个我修改过的 sql,我从 Peter Larsson 的 Island and Gaps 解决方案(链接)获得:

WITH cteIslands ( employeeid, timetype, logdate, logtime, grp) 
       AS ( SELECT employeeid, timetype, logdate, logtime, 
                 ROW_NUMBER() 
                    OVER ( ORDER BY employeeid, logdate, logtime ) 
                 - ROW_NUMBER() 
                    OVER ( ORDER BY timetype, employeeid, 
                                    logdate, logtime ) AS grp 
             FROM timeclock
           ),
      cteGrouped ( employeeid, timetype, logdate, logtime ) 
      AS ( SELECT employeeid, MIN(timetype), logdate, 
                  CASE WHEN MIN(timetype) = 'I' 
                       THEN MIN(logtime) 
                       ELSE MAX(logtime) 
                  END AS logtime
           FROM cteIslands 
           GROUP BY employeeid, logdate, grp 
         ) 
select * from cteIslands
order by employeeid, logdate, logtime

以上在满足删除重复条目方面效果很好,但现在我似乎无法获得孤立条目。我认为 LEAD 或 LAG 可以用于此,但我是 postgresql 的新手。我希望这里有人可以帮助我。

编辑:我不知何故需要添加一个我可以使用的新字段,以便我知道哪些记录是孤立的。类似于下表:

EMPID   TYPE    LOGDATE     LOGTIME    ORPHAN_FLAG
1          I    2013-01-01  07:00:00    0
1          O    2013-01-01  16:01:00    0
1          I    2013-01-02  07:00:00    0
1          O    2013-01-02  16:30:00    0
2          I    2013-01-01  07:00:00    0
2          O    2013-01-01  16:00:00    0
2          I    2013-01-02  06:30:00    0
2          O    2013-01-02  15:30:00    0
2          I    2013-01-02  16:30:00    0
2          O    2013-01-02  23:30:00    0
3          I    2013-01-01  06:30:00    0
3          O    2013-01-02  16:30:00    0
4          I    2013-01-01  20:30:00    0
4          O    2013-01-02  05:30:00    0
5          O    2013-01-01  20:30:00    1   <--- NO MATCHING IN
5          I    2013-01-02  05:30:00    1   <--- NO MATCHING OUT
4

1 回答 1

0

首先,我认为你应该重新考虑你的设计。在没有打卡的情况下记录打卡条目没有什么意义,您可以使用部分索引等东西来确保打卡的条目在没有打卡条目时易于查找。

因此,我首先考虑将您的存储表移动到以下位置:

CREATE TABLE timeclock(
     employeeid INT
     , logdate DATE
     , logintime TIME
     , logouttime time
     , timetype VARCHAR(1)
);

坏消息是,如果你不能这样做,你的孤立报表将很难很好地执行,因为你正在做一个自连接,你希望一个大表中的每一行都有一个相应的其他条目。这最多需要对表进行两次顺序扫描,最坏情况下需要使用嵌套循环索引扫描进行顺序扫描(假设索引正确,或者,嵌套循环顺序扫描会更糟)。

如果您在日期之间(晚上 11 点打卡,凌晨 2 点打卡)处理这个问题,将很难避免这个问题。

现在,由于除了孤立记录之外,您的 CTE 工作正常,我的建议是与同一张表上的另一个查询联合,以查找在您当前查询中未正确找到的那些。

于 2013-12-10T03:20:42.463 回答