在时间组和支点语句中选择最新和最早的时间

时间:2018-12-31 01:43:05

标签: sql oracle oracle11g pivot aggregate-functions

我的出勤数据包含用户名,时间和状态(INOUT)。我想显示包含姓名的签到数据以及签入/签出时间。我希望一个人每天最多可以进出两次。数据如下:

Commercial Photography

如您所见,我的问题是,对于同一登录尝试,一个人可以在不同的秒内拥有多个数据条目。这是因为我从指纹考勤扫描仪获取数据,并且在某些情况下机器会进行多次输入,有时只需5-10秒。我想选择这样的数据:

Commercial Photography

如何确定正确的登录尝试时间,然后选择数据透视表?

1 个答案:

答案 0 :(得分:3)

首先,您需要通过删除重复的条目来规范化数据。在您的情况下,这是一个挑战,因为不容易将重复的数据标识为重复的数据。您可以做一些假设。在下面,我假设没有人会在两分钟的时间内进行多次登录尝试。您可以先使用通用表表达式(CTE,使用WITH子句)来完成此操作。

在CTE中,您可以使用LAG功能。本质上,这段代码说的是“对于用户和条目类型的每个分区,如果先前的值在该值的2分钟之内,则输入一个数字,否则输入null。”我选择null作为保留值的标志,因为第一项的LAG将为null。因此,您的CTE只会返回不同尝试的条目事件(ID)表。

现在,您准备一个PIVOT将从中提取的另一个CTE,其中包含表中的所有内容,但仅包含您关心的条目ID。 PIVOT将查看您的IN / OUT时间的MIN / MAX。

WITH UNIQUE_LOGINS AS (
    SELECT ID FROM LOGIN_TABLE 
    WHERE CASE WHEN LAG(TIME, 1, 0) OVER (PARTITION BY USERNAME, STATUS ORDER BY TIME) 
              + (2/60/24) < TIME THEN NULL ELSE 1 END IS NULL ),   -- Times within 2 minutes
TEMP_FOR_PIVOT AS (
    SELECT USERNAME, TIME, STATUS FROM LOGIN_TABLE WHERE ID IN (SELECT ID FROM UNIQUE_LOGINS)
)
SELECT * FROM TEMP_FOR_PIVOT
PIVOT (
    MIN(TIME), MAX(TIME) FOR STATUS IN ('IN', 'OUT')
)

从那里,如果您需要重新排列或重命名列,则只需将最后一个SELECT放入另一个CTE中,然后从中选择值即可。这里还有关于PIVOT的更多信息:Rotate/pivot table with aggregation in Oracle