Domanda

I have a table in Oracle that tracks user login and logout/timeout. I am making a select query to show me the concurrent users by hour for the past 7 days. I have a base query, but it does not properly count users who's session crosses midnight.

Bit of information on the data/my query:

  • Logintracking holds all user login actions such as login/logout/timeout actions. Each action is on a separate row.
  • Attemptdate is when the action took place
  • Attemptresult7 is the result of the login action (LOGIN/LOGOUT/TIMEOUT)
  • Maxsessionuid is the users session id, which can be used to link the login with the logout/timeout.
  • I'm using a left outer self join to match up logins with logouts based on the session id. Since the user may still be logged in I replace null logout dates with sysdate.
  • I group data by year/month/day and remove any records where the user might have logged in twice with a distinct. The same user logged in 10 times is only considered 1 concurrent user in this report. (This part isn't really working either, as my distinct is on both login and logout hour, which would probably be different between sessions. I really need to combine overlapping sessions for the same user...)
  • I count the number of concurrent users by seeing if each hour from 0 to 23 is between their login and logout (which of course won't work for sessions that cross days)

--My Oracle Query so far:

Select Lyear,
        Lmonth,
        Lday,
        Sum(Case When 0 Between Lhour And Ohour Then 1 Else 0 End) H00,
        Sum(CASE WHEN 1 between LHour and OHour Then 1 Else 0 End) H01,
        Sum(CASE WHEN 2 between LHour and OHour Then 1 Else 0 End) H02,
        Sum(Case When 3 Between Lhour And Ohour Then 1 Else 0 End) H03,
        Sum(CASE WHEN 4 between LHour and OHour Then 1 Else 0 End) H04,
        Sum(CASE WHEN 5 between LHour and OHour Then 1 Else 0 End) H05,
        Sum(CASE WHEN 6 between LHour and OHour Then 1 Else 0 End) H06,
        Sum(CASE WHEN 7 between LHour and OHour Then 1 Else 0 End) H07,
        Sum(CASE WHEN 8 between LHour and OHour Then 1 Else 0 End) H08,
        Sum(Case When 9 Between Lhour And Ohour Then 1 Else 0 End) H09,
        Sum(CASE WHEN 10 between LHour and OHour Then 1 Else 0 End) H10,
        Sum(CASE WHEN 11 between LHour and OHour Then 1 Else 0 End) H11,
        Sum(CASE WHEN 12 between LHour and OHour Then 1 Else 0 End) H12,
        Sum(CASE WHEN 13 between LHour and OHour Then 1 Else 0 End) H13,
        Sum(CASE WHEN 14 between LHour and OHour Then 1 Else 0 End) H14,
        Sum(CASE WHEN 15 between LHour and OHour Then 1 Else 0 End) H15,
        Sum(Case When 16 Between Lhour And Ohour Then 1 Else 0 End) H16,
        Sum(Case When 17 Between Lhour And Ohour Then 1 Else 0 End) H17,
        Sum(Case When 18 Between Lhour And Ohour Then 1 Else 0 End) H18,
        Sum(CASE WHEN 19 between LHour and OHour Then 1 Else 0 End) H19,
        Sum(Case When 20 Between Lhour And Ohour Then 1 Else 0 End) H20,
        Sum(Case When 21 Between Lhour And Ohour Then 1 Else 0 End) H21,
        Sum(CASE WHEN 22 between LHour and OHour Then 1 Else 0 End) H22,
        Sum(Case When 23 Between Lhour And Ohour Then 1 Else 0 End) H23
From (    
Select Distinct L1.Userid,
         Extract(Year From L1.Attemptdate) Lyear,  
         Extract(Month From L1.Attemptdate) Lmonth, 
         Extract(Day From L1.Attemptdate) Lday,
    --You can't extract HOUR from a date, must be a timestamp
         Extract(Hour From Cast(L1.Attemptdate As Timestamp)) As Lhour, 
         Extract(Hour From Cast(NVL(L2.Attemptdate,SYSDATE) As Timestamp)) As OHour
  From Maximo.Logintracking L1
        LEFT OUTER JOIN Maximo.Logintracking L2 On
          L1.Maxsessionuid = L2.Maxsessionuid
  Where L1.Attemptresult7 = 'LOGIN' And L2.Attemptresult7 != 'LOGIN'
        And L1.Attemptdate > Trunc( Sysdate)-7
        And L2.Attemptdate > Trunc(Sysdate)-7) Sessions
Group By Lyear, Lmonth, Lday    
ORDER By LYear, LMonth, LDay

The query doesn't have to stay anything like it is now. But the end result should be that I have a x day view of concurrent users by hour.

Related: How to count the number of concurrent users using time interval data?

È stato utile?

Soluzione

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 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top