Oracle
 sql >> Datenbank >  >> RDS >> Oracle

ID-Spalte basierend auf Aktivitätsdaten erstellen

Ich denke, das wird den Zweck erfüllen:

WITH EVENTS AS (SELECT 'abc' usr, to_date('2016-01-01 08:00:00', 'yyyy-mm-dd hh24:mi:ss') event_ts, 'login' event_type FROM dual UNION ALL
                SELECT 'abc' usr, to_date('2016-01-01 08:25:00', 'yyyy-mm-dd hh24:mi:ss') event_ts, 'Stuff' event_type FROM dual UNION ALL
                SELECT 'abc' usr, to_date('2016-01-01 10:00:00', 'yyyy-mm-dd hh24:mi:ss') event_ts, 'Stuff' event_type FROM dual UNION ALL
                SELECT 'abc' usr, to_date('2016-01-01 14:00:00', 'yyyy-mm-dd hh24:mi:ss') event_ts, 'login' event_type FROM dual UNION ALL
                SELECT 'xyz' usr, to_date('2015-12-31 18:00:00', 'yyyy-mm-dd hh24:mi:ss') event_ts, 'login' event_type FROM dual UNION ALL
                SELECT 'xyz' usr, to_date('2016-01-01 08:00:00', 'yyyy-mm-dd hh24:mi:ss') event_ts, 'Logout' event_type FROM dual UNION ALL
                SELECT 'def' usr, to_date('2016-01-01 08:00:00', 'yyyy-mm-dd hh24:mi:ss') event_ts, 'Logout' event_type FROM dual UNION ALL
                SELECT 'def' usr, to_date('2016-01-01 08:15:00', 'yyyy-mm-dd hh24:mi:ss') event_ts, 'Logout' event_type FROM dual)
SELECT usr,
       event_ts,
       event_type,
       SUM(counter) OVER (PARTITION BY usr ORDER BY event_ts) session_id
FROM   (SELECT usr,
               event_ts,
               event_type,
               CASE WHEN LAG(event_type, 1, 'Logout') OVER (PARTITION BY usr ORDER BY event_ts) = 'Logout' THEN 1
                    WHEN event_type = 'Logout' THEN 0
                    WHEN event_ts - LAG(event_ts) OVER (PARTITION BY usr ORDER BY event_ts) > 1/24 THEN 1
                    WHEN event_type = 'login' THEN 1
                    ELSE 0
               END counter
        FROM   EVENTS);

USR EVENT_TS            EVENT_TYPE SESSION_ID
--- ------------------- ---------- ----------
abc 2016-01-01 08:00:00 login               1
abc 2016-01-01 08:25:00 Stuff               1
abc 2016-01-01 10:00:00 Stuff               2
abc 2016-01-01 14:00:00 login               3
def 2016-01-01 08:00:00 Logout              1
def 2016-01-01 08:15:00 Logout              2
xyz 2015-12-31 18:00:00 login               1
xyz 2016-01-01 08:00:00 Logout              1

Diese Lösung beruht auf dem logischen Kurzschluss, der im CASE-Ausdruck stattfindet, und auf der Tatsache, dass event_type nicht null ist. Es wird auch davon ausgegangen, dass mehrere Abmeldungen hintereinander als separate Sitzungen gezählt werden:

  1. Wenn die vorherige Zeile eine Logout-Zeile war (und wenn es keine vorherige Zeile gibt – d. h. für die erste Zeile im Satz – behandeln Sie es so, als ob eine Logout-Zeile vorhanden wäre), möchten wir den Zähler um eins erhöhen. (Abmeldungen beenden die Sitzung, sodass wir nach einer Abmeldung immer eine neue Sitzung haben.)
  2. Wenn die aktuelle Zeile ein Logout ist, dann beendet dies die bestehende Sitzung. Daher sollte der Zähler nicht erhöht werden.
  3. Wenn die Zeit der aktuellen Zeile mehr als eine Stunde von der vorherigen Zeile entfernt ist, erhöhen Sie den Zähler um eins.
  4. Wenn die aktuelle Zeile eine Login-Zeile ist, dann ist es eine neue Sitzung, also erhöhen Sie den Zähler um eins.
  5. In allen anderen Fällen erhöhen wir den Zähler nicht.

Sobald wir das getan haben, müssen wir nur noch eine laufende Summe auf dem Zähler erstellen.