У меня есть таблица, хранящая элементы массива по массиву, к которому они принадлежат, и их индекс в массиве.Это казалось разумным, потому что массивы должны были быть редкими, а их элементы обновляться индивидуально.Допустим, это таблица:
CREATE TABLE values (
pk TEXT,
i INTEGER,
value REAL,
PRIMARY KEY (pk, i)
);
pk | i | value
----+---+-------
A | 0 | 17.5
A | 1 | 32.7
A | 3 | 5.3
B | 1 | 13.5
B | 2 | 4.8
B | 4 | 89.1
Теперь я хотел бы получить их в виде реальных массивов, т.е. {17.5, 32.7, NULL, 53}
для A и {NULL, 13.5, 4.8, NULL, 89.1}
для B.
Я бы ожидал, что это легко сделать с помощью группирующего запроса и соответствующей агрегатной функции.Однако оказалось, что нет такой функции, которая бы помещала элементы в массив по его индексу (или по нижнему индексу, как его называет postgres).Было бы намного проще, если бы элементы были последовательными - я просто мог бы использовать array_agg
с ORDER BY i
.Но я хочу получить нулевые значения в массивах результатов.
В результате я получил этого монстра:
SELECT
pk,
ARRAY( SELECT
( SELECT value
FROM values innervals
WHERE innervals.pk = outervals.pk AND i = generate_series
)
FROM generate_series(0, MAX(i))
ORDER BY generate_series -- is this really necessary?
)
FROM values outervals
GROUP BY pk;
Дважды SELECT … FROM values
ужасно, а планировщик запросов - нетКажется, я могу оптимизировать это.
Есть ли простой способ ссылаться на сгруппированные строки как отношение в подзапросе , чтобы я мог просто SELECT value FROM generate_series(0, MAX(i)) LEFT JOIN ???
?
Было бы более уместно решить эту проблему, определив пользовательскую агрегатную функцию ?
Edit : Кажется,то, что я искал, возможно с несколькими аргументами unnest
и array_agg
, хотя это не особенно элегантно:
SELECT
pk,
ARRAY( SELECT val
FROM generate_series(0, MAX(i)) AS series (series_i)
LEFT OUTER JOIN
unnest( array_agg(value ORDER BY i),
array_agg(i ORDER BY i) ) AS arr (val, arr_i)
ON arr_i = series_i
ORDER BY series_i
)
FROM values
GROUP BY pk;
Планировщик запросов даже, кажется, понимает, что может выполнитьотсортированные слияния JOIN
на отсортированных series_i
и arr_i
, хотя мне нужно приложить еще больше усилий для реального понимания вывода EXPLAIN
. Редактировать 2 : На самом деле это хеш-соединение между series_i
и arr_i
, только агрегирование внешних групп использует "отсортированную" стратегию.