Postgresql Pivot с использованием кросс-таблицы - PullRequest
1 голос
/ 01 ноября 2019

У меня проблемы с использованием crosstab() в postgresql-11.

Вот моя таблица,

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

Таблица отслеживает события в других таблицах. Он содержит

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) 

Вот примеры данных к нему.

                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

Учитывая временную метку, я хочу перечислить все текущие события в это время. Это можно сделать с помощью критериев

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

Поэтому я попытался использовать crosstab() для поворота таблицы по столбцам table_name, status и timestamp. Мой запрос:

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;

Результат запроса:

 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

Но мой ожидаемый результат:

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

Как мне достичь ожидаемоговыход? Или есть другой способ, кроме кросс-таблицы?

1 Ответ

2 голосов
/ 01 ноября 2019

Я бы использовал для этого самостоятельное соединение. Чтобы сохранить строки на одном уровне и в таблице вместе, вы можете использовать оконную функцию для присвоения им чисел, чтобы их можно было различать.

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;

Это предполагает, что строки с status = 'end' никогда не будети более ранняя временная метка, а затем соответствующая строка с status = 'start'

Онлайн-пример: https://rextester.com/QYJK57764

...