Кросс-таблица PostgreSQL не работает должным образом - PullRequest
0 голосов
/ 02 апреля 2019

В этом примере я ожидаю, что в итоговой сводной таблице будут значения для 4 столбцов, но вместо этого есть только значения для 2.

Он должен был вернуть что-то вроде этого:

| time | trace1 | trace2 | trace3 | trace4 |
| -----------------------------------------|
|   t  |   v    |   v    |   v    |   v    |
|   t  |   v    |   v    |   v    |  null  |
|   t  |  null  |   v    |   v    |   v    |
|   t  |   v    |   v    |  null  |   v    |
|   t  |   v    |  null  |   v    |   v    |
|------------------------------------------|

но я получил это вместо:

| time | trace1 | trace2 | trace3 | trace4 |
| -----------------------------------------|
|   t  |   v    |   v    |  null  |  null  |
|   t  |   v    |   v    |  null  |  null  |
|   t  |   v    |   v    |  null  |  null  |
|   t  |   v    |  null  |  null  |  null  |
|   t  |   v    |  null  |  null  |  null  |
|------------------------------------------|

Еще хуже, если я уберу

order by unixdatetime

, все будет разбито только на 1 столбец, как показано ниже:

| time | trace1 | trace2 | trace3 | trace4 |
| -----------------------------------------|
|   t  |   v    |  null  |  null  |  null  |
|   t  |   v    |  null  |  null  |  null  |
|   t  |   v    |  null  |  null  |  null  |
|   t  |   v    |  null  |  null  |  null  |
|   t  |   v    |  null  |  null  |  null  |
|------------------------------------------|

Вот код:

select * 
from crosstab(
    $$
    select 
        unixdatetime, 
        gaugesummaryid, 
        value::double precision 
    from 
    (values
        (1546300800,187923,1.5),
        (1546387200,187923,1.5),
        (1546473600,187923,1.5),
        (1546560000,187923,1.75),
        (1546646400,187923,1.75),
        (1546732800,187923,1.75),
        (1546819200,187923,1.75),
        (1546905600,187923,1.5),
        (1546992000,187923,1.5),
        (1547078400,187923,1.5),
        (1547164800,187923,1.5),
        (1547337600,187924,200),
        (1547424000,187924,200),
        (1547510400,187924,200),
        (1547596800,187924,200),
        (1547683200,187924,200),
        (1547769600,187924,200),
        (1547856000,187924,200),
        (1547942400,187924,200),
        (1548028800,187924,200),
        (1548115200,187924,200),
        (1548201600,187924,200),
        (1548288000,187924,200),
        (1546300800,187926,120),
        (1546387200,187926,120),
        (1546473600,187926,120),
        (1546560000,187926,110),
        (1546646400,187926,110),
        (1546732800,187926,110),
        (1546819200,187926,110),
        (1546905600,187926,115),
        (1546992000,187926,115),
        (1547078400,187926,115),
        (1547942400,187927,100),
        (1548028800,187927,100),
        (1548115200,187927,100),
        (1548201600,187927,100),
        (1548288000,187927,100)
    ) as t (unixdatetime, gaugesummaryid, value)
    order by unixdatetime
    $$
    ) as final_result (
        unixdatetime int, 
        trace1 double precision, 
        trace2 double precision, 
        trace3 double precision, 
        trace4 double precision
        );

Вот ссылка на случай, если вы захотите поиграть:

https://dbfiddle.uk/?rdbms=postgres_11&fiddle=2c4f6098fb89b78898ba1bf6afa7f439

Как получить желаемый результат?

Ответы [ 3 ]

0 голосов
/ 02 апреля 2019

Я бы рекомендовал вам использовать предложение filter (where ...) вместо сводной таблицы.

select
    unixdatetime,
    min(value) filter (where gaugesummaryid = 187923) as trace_1,
    min(value) filter (where gaugesummaryid = 187924) as trace_2,
    min(value) filter (where gaugesummaryid = 187926) as trace_3,
    min(value) filter (where gaugesummaryid = 187927) as trace_4
from table
group by 1;

Обратите внимание, что вы должны использовать агрегатную функцию, чтобы иметь возможность использовать предложение.В вашем случае не имеет значения, используете ли вы min, max, avg или sum.

0 голосов
/ 02 апреля 2019

Хотя некоторые из целевых значений могут отсутствовать, вам нужна форма с двумя аргументами crosstab() (, как в случае с unutbu ).
Но не имеет смысла использовать запрос, дающий нестабильные результаты. Используйте выражение VALUES (или подобное) в качестве второго параметра, чтобы обеспечить стабильный набор целевых столбцов в синхронизации с результирующим списком определений столбцов. Как:

SELECT * 
FROM   crosstab(
   $$
   SELECT *
   FROM  (
      VALUES
      (bigint '1546300800', 187923, float8 '1.5')
    , (1546387200,187923,1.5)
    , (1546473600,187923,1.5)
 -- , ...
    , (1548288000,187927,100)
   ) t (unixdatetime, gaugesummaryid, value)
   ORDER BY 1,2
   $$
 <b>, 'VALUES (187923), (187924), (187926), (187927)'</b>    -- !!
   ) final_result (unixdatetime int
                 , trace1 float8
                 , trace2 float8
                 , trace3 float8
                 , trace4 float8);

дБ <> скрипка здесь

Подробное объяснение:

Было бы неплохо получить результаты для динамического количества целевых столбцов из одного запроса. Увы, SQL так не работает. Существуют различные обходные пути. См:

0 голосов
/ 02 апреля 2019

Используйте 2-аргументную форму функции crosstab:

SELECT * 
FROM crosstab(
        $$
        SELECT 
                unixdatetime, 
                gaugesummaryid, 
                value::double precision 
        FROM test
        ORDER BY unixdatetime
        $$
        , 'SELECT DISTINCT gaugesummaryid FROM test ORDER BY 1 LIMIT 4'
        ) as final_result (
                unixdatetime int, 
                trace1 double precision, 
                trace2 double precision, 
                trace3 double precision, 
                trace4 double precision
                )

дает

| unixdatetime | trace1 | trace2 | trace3 | trace4 |
|--------------+--------+--------+--------+--------|
|   1546300800 |    1.5 |        |    120 |        |
|   1546387200 |    1.5 |        |    120 |        |
|   1546473600 |    1.5 |        |    120 |        |
|   1546560000 |   1.75 |        |    110 |        |
|   1546646400 |   1.75 |        |    110 |        |
|   1546732800 |   1.75 |        |    110 |        |
|   1546819200 |   1.75 |        |    110 |        |
|   1546905600 |    1.5 |        |    115 |        |
|   1546992000 |    1.5 |        |    115 |        |
|   1547078400 |    1.5 |        |    115 |        |
|   1547164800 |    1.5 |        |        |        |
|   1547337600 |        |    200 |        |        |
|   1547424000 |        |    200 |        |        |
|   1547510400 |        |    200 |        |        |
|   1547596800 |        |    200 |        |        |
|   1547683200 |        |    200 |        |        |
|   1547769600 |        |    200 |        |        |
|   1547856000 |        |    200 |        |        |
|   1547942400 |        |    200 |        |    100 |
|   1548028800 |        |    200 |        |    100 |
|   1548115200 |        |    200 |        |    100 |
|   1548201600 |        |    200 |        |    100 |
|   1548288000 |        |    200 |        |    100 |

Используя эту настройку:

DROP TABLE IF EXISTS test;
CREATE TABLE test (
        unixdatetime bigint, 
        gaugesummaryid int, 
        value double precision 
);
INSERT INTO test VALUES
        (1546300800,187923,1.5),
        (1546387200,187923,1.5),
        (1546473600,187923,1.5),
        (1546560000,187923,1.75),
        (1546646400,187923,1.75),
        (1546732800,187923,1.75),
        (1546819200,187923,1.75),
        (1546905600,187923,1.5),
        (1546992000,187923,1.5),
        (1547078400,187923,1.5),
        (1547164800,187923,1.5),
        (1547337600,187924,200),
        (1547424000,187924,200),
        (1547510400,187924,200),
        (1547596800,187924,200),
        (1547683200,187924,200),
        (1547769600,187924,200),
        (1547856000,187924,200),
        (1547942400,187924,200),
        (1548028800,187924,200),
        (1548115200,187924,200),
        (1548201600,187924,200),
        (1548288000,187924,200),
        (1546300800,187926,120),
        (1546387200,187926,120),
        (1546473600,187926,120),
        (1546560000,187926,110),
        (1546646400,187926,110),
        (1546732800,187926,110),
        (1546819200,187926,110),
        (1546905600,187926,115),
        (1546992000,187926,115),
        (1547078400,187926,115),
        (1547942400,187927,100),
        (1548028800,187927,100),
        (1548115200,187927,100),
        (1548201600,187927,100),
        (1548288000,187927,100);
...