Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

To pivot a table based on a specific event value using Query

I want to make Table A like Table B. I'd like to see what events the User caused before the Purchase event. I've used row_number() over (partition by client_id, event_type order by time) and it's simply a pivot. How do I make logic?

Table A

client_id   event_type  count      time 
    A         cart        1     AM 12:00:00 
    A         view        4     AM 12:01:00
    A         purchase    2     AM 12:05:00
    A         view        2     AM 12:10:00 
    B         view        3     AM 12:03:00
    B         purchase    1     AM 12:05:00
    B         view        2     AM 12:10:00 

Table B

client_id     view     cart   purchase 
    A           4        1        2     
    A           2        0        0
    B           3        0        1
    B           2        0        0
like image 685
user5740635 Avatar asked Mar 01 '26 14:03

user5740635


1 Answers

Here is a way of doing this, i define a group of events as belonging to a single "session/activity" before purchase using the block grp_split.

Then i get this grouping correctly done in the block x, by replacing null values with the previously not null value using the max(grp) over(partition by client_id order by time1) as grp2.

After that its a matter of pivoting the columns for view,cart and purchase

with data
  as (
    select 'A' as client_id,'cart'     as event_type   , 1  as count1, cast('AM 12:00:00' as time) as time1 union all 
    select 'A' as client_id,'view'     as event_type   , 4  as count1, cast('AM 12:01:00' as time) as time1 union all
    select 'A' as client_id,'purchase' as event_type   , 2  as count1, cast('AM 12:05:00' as time) as time1 union all
    select 'A' as client_id,'view'     as event_type   , 2  as count1, cast('AM 12:10:00' as time) as time1 union all
    select 'B' as client_id,'view'     as event_type   , 3  as count1, cast('AM 12:03:00' as time) as time1 union all
    select 'B' as client_id,'purchase' as event_type   , 1  as count1, cast('AM 12:05:00' as time) as time1 union all
    select 'B' as client_id,'view' as event_type   , 2  as count1, cast('AM 12:10:00' as time) as time1 
     )
   ,grp_split
   as(
select case when lag(event_type) over(partition by client_id order by time1)='purchase' 
              or lag(event_type) over(partition by client_id order by time1) is null 
             then
                 row_number() over(partition by client_id order by time1)
        end as grp
      ,*
  from data
      )
 select x.client_id
       ,max(case when event_type='view' then count1 else 0 end) as view
       ,max(case when event_type='cart' then count1 else 0 end) as cart
       ,max(case when event_type='purchase' then count1 else 0 end) as purchase
  from (
  select *
        ,max(grp) over(partition by client_id order by time1) as grp2
    from grp_split
       )x
  group by client_id
           ,grp2 
  order by client_id

output

+-----------+------+------+----------+
| client_id | view | cart | purchase |
+-----------+------+------+----------+
| A         |    4 |    1 |        2 |
| A         |    2 |    0 |        0 |
| B         |    3 |    0 |        1 |
| B         |    2 |    0 |        0 |
+-----------+------+------+----------+

working example

https://dbfiddle.uk/?rdbms=postgres_12&fiddle=aeeb0878b9094e061c469bb0efb7a024

like image 171
George Joseph Avatar answered Mar 03 '26 03:03

George Joseph



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!