postgresql timeclock条目没有匹配对

时间:2013-11-12 07:06:02

标签: sql postgresql

我有一张桌子:

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时间,而忽略重复的条目 并识别孤立条目(没有匹配的IN或OUT),以便我可以将它放在一个单独的列表中以通知缺失的条目。

到目前为止,我已经修改了这个我从Peter Larsson的Island and Gaps解决方案中获得的SQL(link):

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

1 个答案:

答案 0 :(得分:0)

首先,我认为你应该重新考虑一下你的设计。在没有时钟输入的情况下记录时钟输出条目是没有意义的,并且您可以使用部分索引之类的东西来确保当没有时钟输入时,时钟输入条目很容易查找。

所以我首先考虑将存储表移动到:

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

坏消息是,如果你不能这样做,你的孤儿报告将很难很好地表现,因为你正在进行自我加入,你希望大表中的每一行都有相应的其他条目。这最多需要在表上进行两次顺序扫描,最坏的情况是使用嵌套循环索引扫描进行顺序扫描(假设适当的索引,替代方案,嵌套循环顺序扫描会更糟)。

处理日期之间的翻转(晚上11点钟,凌晨2点钟出)会很难避免这个问题。

既然你的CTE工作正常,除了孤儿记录,我的建议是在同一个表上找另一个查询,寻找那些在当前查询中找不到的查询。