1

I have trouble using crosstab() in postgresql-11.

Here is my table,

CREATE TABLE monitor(tz timestamptz, level int, table_name text, status text);

The table monitors events on other tables. It contains

table_name (table on which the event occurred)
timestamp(time at which the event occurred)
level (level of the event)
status of the event (start/end of the event) 

Here is the sample data to it.

                tz                | level | status |  table_name  
----------------------------------+-------+--------+--------------
 2019-10-24 16:18:34.89435+05:30  |     2 | start  | test_table_2
 2019-10-24 16:18:58.922523+05:30 |     2 | end    | test_table_2
 2019-11-01 10:31:08.948459+05:30 |     3 | start  | test_table_3
 2019-11-01 10:41:22.863529+05:30 |     3 | end    | test_table_3
 2019-11-01 10:51:44.009129+05:30 |     3 | start  | test_table_3
 2019-11-01 12:35:23.280294+05:30 |     3 | end    | test_table_3

Given a timestamp, I want to list out all current events at that time. It could be done using the criteria,

start_time >= 'given_timestamp' and end_time <= 'given_timestamp'

So I tried to use crosstab() to pivot the table over columns table_name,status and timestamp. My query is,

with q1 (table_name, start_time,end_time) as
    (select * from crosstab
    ('select table_name, status, tz from monitor ')
    as finalresult (table_name text, start_time timestamptz, end_time timestamptz)), 
q2 (level,start_time,end_time) as 
    (select * from crosstab('select level, status, tz from monitor ') 
    as finalresult (level int, start_time timestamptz, end_time timestamptz)) 
select q1.table_name,q2.level,q1.start_time,q1.end_time 
    from q1,q2 
    where q1.start_time=q2.start_time;

The output of the query is,

 table_name  | level |            start_time            |             end_time             
--------------+-------+----------------------------------+----------------------------------
 test_table_2 |     2 | 2019-10-24 16:18:34.89435+05:30  | 2019-10-24 16:18:58.922523+05:30
 test_table_3 |     3 | 2019-11-01 10:31:08.948459+05:30 | 2019-11-01 10:41:22.863529+05:30

But my expected output is,

table_name  | level |            start_time            |             end_time             
--------------+-------+----------------------------------+----------------------------------
 test_table_2 |     2 | 2019-10-24 16:18:34.89435+05:30  | 2019-10-24 16:18:58.922523+05:30
 test_table_3 |     3 | 2019-11-01 10:31:08.948459+05:30 | 2019-11-01 10:41:22.863529+05:30
 test_table_3 |     3 | 2019-11-01 10:51:44.009129+05:30 | 2019-11-01 12:35:23.280294+05:30

How do I achieve the expected output? Or is there any better way other than crosstab?

1 Answer 1

2

I would use a self join for this. To keep the rows on the same level and table together you can use a window function to assign numbers to them so they can be distinguished.

with numbered as (
  select tz, level, table_name, status, 
         row_number() over (partition by table_name, status order by tz) as rn
  from monitor
)
select st.table_name, st.level, st.tz as start_time, et.tz as end_time
from numbered as st
  join numbered as et on st.table_name = et.table_name
                     and et.status = 'end'
                     and et.level = st.level
                     and et.rn = st.rn
where st.status = 'start'
order by st.table_name, st.level;

This assumes that there will never be a row with status = 'end' and an earlier timestamp then the corresponding row with status = 'start'

Online example: https://rextester.com/QYJK57764

Sign up to request clarification or add additional context in comments.

2 Comments

Self join produces wrong results when there are two consective events of same level for a table. please see the updated sample data
Worked! Thanks :) But is there a way to do it with crosstab??

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.