0

I have attandance data that contains a username, time, and status (IN or OUT). I want to show attendance data that contains a name, and the check in/out times. I expect a person to check in and out no more than twice a day. The data looks like this:

Commercial Photography

As you can see, my problem is that one person can have multiple data entries in different seconds for the same login attempt. This is because I get data from a fingerprint attendace scanner, and the machine in some cases makes multiple entries, sometimes just within 5-10 seconds. I want to select the data to be like this:

Commercial Photography

How can I identify the proper time for the login attempt, and then select the data with a pivot?

SandPiper
  • 2,816
  • 5
  • 30
  • 52
Dwiky Restu
  • 70
  • 1
  • 8

1 Answers1

3

First, you need to normalize your data by removing the duplicate entries. In your situation, that's a challenge because the duplicated data isn't easily identified as a duplicate. You can make some assumptions though. Below, I assume that no one will make multiple login attempts in a two minute window. You can do this by first using a Common Table Expression (CTE, using the WITH clause).

Within the CTE, you can use the LAG function. Essentially what this code is saying is "for each partition of user and entry type, if the previous value was within 2 minutes of this value, then put a number, otherwise put null." I chose null as the flag that will keep the value because LAG of the first entry is going to be null. So, your CTE will just return a table of entry events (ID) that were distinct attempts.

Now, you prepare another CTE that a PIVOT will pull from that has everything from your table, but only for the entry IDs you cared about. The PIVOT is going to look over the MIN/MAX of your IN/OUT times.

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')
)

From there, if you need to rearrange or rename your columns, then you can just put that last SELECT into yet another CTE and then select your values from it. There is some more about PIVOT here: Rotate/pivot table with aggregation in Oracle

SandPiper
  • 2,816
  • 5
  • 30
  • 52
  • sorry for late, i tried now and theres an error says : ORA-30483: window functions are not allowed here, i think error is in WITH AS – Dwiky Restu Jan 02 '19 at 02:36