How to pivot this table in SQL

2019-08-17 05:23发布

I came across this issue when trying to make use of this "active users" table from Microsoft NAV. What I got asked to do is a Dashboard in Power BI or other tool that will allow the company I work for to understand how many users are active on the NAV system at any point in time. I found a DAX formula in Power BI that could do the trick - but it requires the following table transformation:

I am trying to do this in SQL Management Studio:

My SQL Server is Microsoft SQL Azure (RTM) - 12.

How could I pivot this NAV table below with the following structure knowing that Session ID might repeat further down the line?

Session ID  |    Event Datetime       | Event Type
350              2017-07-01 01:00       Logon
350              2017-08-01 02:00       Logoff
351              2017-07-01 02:00       Logon
351              2017-08-01 03:00       Logoff
350              2017-09-01 01:00       Logon
350              2017-09-01 02:00       Logoff

The final result would be each Session ID against their Logon and Logoff time (allowing duplicates if Session ID repeats like in this example)

Thanks a lot in advance.

Best

Andre

标签: sql pivot
2条回答
姐就是有狂的资本
2楼-- · 2019-08-17 05:52

This is TSQL code and will run on an Azure database. I think this will get you the results you are looking for.

DECLARE @ActiveUsersLog AS TABLE
      (
          sessionId     INT
         ,EventDateTime DATETIME
         ,EventType     VARCHAR(50)
      );

INSERT INTO @ActiveUsersLog
     (
         sessionId
        ,EventDateTime
        ,EventType
     )
VALUES
     (350, '2017-07-01 01:00', 'Logon')
    ,(350, '2017-08-01 02:00', 'Logoff')
    ,(351, '2017-07-01 02:00', 'Logon')
    ,(351, '2017-08-01 03:00', 'Logoff')
    ,(350, '2017-09-01 01:00', 'Logon')
    ,(350, '2017-09-01 02:00', 'Logoff');

WITH cte_logon
    AS (
           SELECT aul.sessionId
                 ,aul.EventDateTime
                 ,seq = RANK() OVER (PARTITION BY aul.sessionId ORDER BY aul.EventDateTime)
             FROM @ActiveUsersLog AS aul
            WHERE aul.EventType = 'Logon'
       )
    ,cte_logoff
    AS (
           SELECT aul.sessionId
                 ,aul.EventDateTime
                 ,seq = RANK() OVER (PARTITION BY aul.sessionId ORDER BY aul.EventDateTime)
             FROM @ActiveUsersLog AS aul
            WHERE aul.EventType = 'Logoff'
       )
SELECT o.sessionId
      ,LogonTime = o.EventDateTime
      ,LogoffTime = f.EventDateTime
  FROM cte_logon AS o
      LEFT OUTER JOIN cte_logoff AS f
          ON o.sessionId = f.sessionId
             AND o.seq = f.seq;

If you are only looking for active users then you would add this where clause: (make sure to remove the semicolon at the end of the code above before adding a where clause)

where f.EventDateTime is null
查看更多
可以哭但决不认输i
3楼-- · 2019-08-17 06:02

Without knowing the flavour of SQL, I can only give you basic advice.

By performing an inner join with both sides lining to the same table (aliasing appropriately) matching on the session_id of both sides, you can then filter Event Type on one of the aliased tables to equal Logon and Event Type on the other aliased table to match Logoff.

This method should work on just about any form of SQL I've used, as it's core functionality of SQL.

查看更多
登录 后发表回答