मुझे लगता है कि यह चाल चलेगा:
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
यह समाधान तर्क-शॉर्ट सर्किटिंग पर निर्भर करता है जो CASE अभिव्यक्ति में होता है और यह तथ्य कि event_type शून्य नहीं है। यह भी मानता है कि एक पंक्ति में एकाधिक लॉगआउट को अलग सत्रों के रूप में गिना जाता है:
- यदि पिछली पंक्ति एक लॉगआउट पंक्ति थी (और यदि कोई पिछली पंक्ति नहीं है - यानी सेट में पहली पंक्ति के लिए - इसे लॉगआउट पंक्ति के रूप में मानें), तो हम काउंटर को एक से बढ़ाना चाहते हैं। (लॉगआउट सत्र को समाप्त करते हैं, इसलिए लॉगआउट के बाद हमारे पास हमेशा एक नया सत्र होता है।)
- यदि वर्तमान पंक्ति लॉगआउट है, तो यह मौजूदा सत्र को समाप्त कर देता है। इसलिए, काउंटर को नहीं बढ़ाया जाना चाहिए।
- यदि वर्तमान पंक्ति का समय पिछली पंक्ति से एक घंटे से अधिक है, तो काउंटर को एक से बढ़ा दें।
- यदि वर्तमान पंक्ति एक लॉगिन पंक्ति है, तो यह एक नया सत्र है, इसलिए काउंटर को एक से बढ़ा दें।
- किसी अन्य मामले के लिए, हम काउंटर नहीं बढ़ाते हैं।
एक बार जब हम ऐसा कर लेते हैं, तो यह काउंटर पर कुल रन बनाने की बात है।