Somewhere along the way my pretty-simply-neatly-written query became this monster (seems to work, so one good thing about it at least):
CREATE TABLE logintracking (
userid NUMBER,
maxsessionuid NUMBER,
Attemptdate DATE,
attemptresult7 VARCHAR2(20)
);
INSERT INTO logintracking VALUES (1, 100, TO_DATE('27-10-2013 10:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGIN');
INSERT INTO logintracking VALUES (1, 100, TO_DATE('27-10-2013 12:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGOUT');
INSERT INTO logintracking VALUES (1, 101, TO_DATE('27-10-2013 11:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGIN');
INSERT INTO logintracking VALUES (1, 101, TO_DATE('27-10-2013 15:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGOUT');
INSERT INTO logintracking VALUES (1, 102, TO_DATE('27-10-2013 23:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGIN');
INSERT INTO logintracking VALUES (1, 102, TO_DATE('28-10-2013 02:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGOUT');
INSERT INTO logintracking VALUES (1, 103, TO_DATE('27-10-2013 20:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGIN');
INSERT INTO logintracking VALUES (1, 103, TO_DATE('28-10-2013 01:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGOUT');
INSERT INTO logintracking VALUES (2, 104, TO_DATE('27-10-2013 23:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGIN');
INSERT INTO logintracking VALUES (2, 104, TO_DATE('28-10-2013 02:00:00', 'DD-MM-YYYY HH24:MI:SS'), 'LOGOUT');
COMMIT;
WITH
hours_of_last_7_days AS (
SELECT TRUNC(SYSDATE, 'HH24') - numtodsinterval(level, 'HOUR') AS hour_val
FROM dual
CONNECT BY level <= 7 * 24
)
SELECT
lyear,
lmonth,
lday,
SUM(DECODE(lhour, 0, 1, 0)) AS H00,
SUM(DECODE(lhour, 1, 1, 0)) AS H01,
SUM(DECODE(lhour, 2, 1, 0)) AS H02,
SUM(DECODE(lhour, 3, 1, 0)) AS H03,
SUM(DECODE(lhour, 4, 1, 0)) AS H04,
SUM(DECODE(lhour, 5, 1, 0)) AS H05,
SUM(DECODE(lhour, 6, 1, 0)) AS H06,
SUM(DECODE(lhour, 7, 1, 0)) AS H07,
SUM(DECODE(lhour, 8, 1, 0)) AS H08,
SUM(DECODE(lhour, 9, 1, 0)) AS H09,
SUM(DECODE(lhour, 10, 1, 0)) AS H10,
SUM(DECODE(lhour, 11, 1, 0)) AS H11,
SUM(DECODE(lhour, 12, 1, 0)) AS H12,
SUM(DECODE(lhour, 13, 1, 0)) AS H13,
SUM(DECODE(lhour, 14, 1, 0)) AS H14,
SUM(DECODE(lhour, 15, 1, 0)) AS H15,
SUM(DECODE(lhour, 16, 1, 0)) AS H16,
SUM(DECODE(lhour, 17, 1, 0)) AS H17,
SUM(DECODE(lhour, 18, 1, 0)) AS H18,
SUM(DECODE(lhour, 19, 1, 0)) AS H19,
SUM(DECODE(lhour, 20, 1, 0)) AS H20,
SUM(DECODE(lhour, 21, 1, 0)) AS H21,
SUM(DECODE(lhour, 22, 1, 0)) AS H22,
SUM(DECODE(lhour, 23, 1, 0)) AS H23
FROM (
SELECT
DISTINCT
sessions.userid,
EXTRACT(YEAR FROM hour_val) AS lyear,
EXTRACT(MONTH FROM hour_val) AS lmonth,
EXTRACT(DAY FROM hour_val) AS lday,
EXTRACT(HOUR FROM CAST(hour_val AS TIMESTAMP)) AS lhour
FROM (
SELECT start_lt.userid, start_lt.attemptdate AS login_date, NVL(end_lt.attemptdate, sysdate) AS logout_date
FROM
logintracking start_lt
LEFT OUTER JOIN logintracking end_lt ON (start_lt.maxsessionuid = end_lt.maxsessionuid AND start_lt.attemptresult7 <> end_lt.attemptresult7)
WHERE
start_lt.attemptresult7 = 'LOGIN'
AND start_lt.attemptdate > Trunc(SYSDATE) - 8
) sessions
JOIN hours_of_last_7_days hd ON (hd.hour_val BETWEEN trunc(sessions.login_date,'HH24') AND trunc(sessions.logout_date,'HH24'))
)
GROUP BY lyear, lmonth, lday
ORDER BY lyear, lmonth, lday
;
Output:
LYEAR LMONTH LDAY H00 H01 H02 H03 H04 H05 H06 H07 H08 H09 H10 H11 H12 H13 H14 H15 H16 H17 H18 H19 H20 H21 H22 H23 ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 2013 10 27 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 2 2013 10 28 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0