Pgsql - сводная таблица с неизвестным количеством столбцов - PullRequest
0 голосов
/ 17 октября 2018

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

В настоящее время я использую функцию colpivot (https://github.com/hnsl/colpivot/blob/master/README.md), и она отлично работает в стандартных запросах, но не в функции, поскольку тип возвращаемого значения должен быть установлен во время вызова.

Подход

Шаг 1:

create  temp table _test (
dt timestamp without time zone, id integer,  NumericValue numeric
)

Шаг 2:

insert into _test(dt , id ,NumericValue)
SELECT DISTINCT "T03017_PSR_LOG"."DateTime", 
    "T03017_PSR_LOG"."ID",
    "T03017_PSR_LOG"."NumericValue"
FROM "T03017_PSR_LOG"
INNER JOIN "T03002_PSR_TAG_REG" ON "T03017_PSR_LOG"."TagID" = "T03002_PSR_TAG_REG"."TagID"
WHERE "T03017_PSR_LOG"."DateTime" > 2018-10-02 AND "T03017_PSR_LOG"."DateTime" < 2018-10-07,    
ORDER BY "DateTime", "ID";

Шаг 3:

select colpivot('_test_pivoted', 'select * from _test', array['tagid'], array['dt'], '#.numericvalue', null);

select * from _test_pivoted order by tagid;

ЕслиЯ запускаю приведенный выше в качестве стандартного запроса, он будет возвращать что-то вроде:

ID   2018-10-03   2018-10-04   2018-10-05   2018-10-06

10   1405717.00   1453189.00   1499992.00   1546791.00
11   359102.00    371282.00    383042.00    395047.00

Мне нужно что-то вроде приведенной выше таблицы, чтобы вернуться из функции, где диапазон datetime будет 2 переменные, переданные в функцию, однакоЯ не могу найти решение для этого, так как я не уверен, как установить тип возвращаемого значения в верхней части функции из-за динамического характера возвращаемых столбцов.

1 Ответ

0 голосов
/ 17 октября 2018

Это может показаться немного странным, но я не знаю, как вернуть переменное количество столбцов, и я думаю, что вам лучше всего использовать массивы.

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

with all_dates as (
  select distinct dt from _test
),
all_ids as (
  select distinct id from _test
)
select id, dt
from all_dates
cross join all_ids

Оттуда я присоединю это обратно к исходному набору данных, чтобы каждый элемент в массиве каждой строки ссылался на одно и то же (т.е. если элемент № 5 из одной строки - ноябрь 2017 года, то это означает, что для каждой строки).

Вот как выглядит весь запрос:

with all_dates as (
  select distinct dt from _test
),
all_ids as (
  select distinct id from _test
),
all_combo as (
  select id, dt
  from all_dates
  cross join all_ids
),
pivot_data as (
  select
    a.dt, a.id, coalesce (t.NumericValue, 0) as NumericValue
  from
    all_combo a
    left join _test t on
      a.id = t.id and
      a.dt = t.dt
  order by
    a.id, a.dt
)
select
  id, array_agg(NumericValue) as valuez
from pivot_data
group by id

Это будет немного повторяющимся (одинаковые значения в каждой строке), но вы также можете включить диапазон дат в виде массива.:

select
  id, array_agg(dt) as dates, array_agg(NumericValue) as valuez
...