Развернуть несколько массивов параллельно
Мой последний вопрос Передача массива для хранения в postgres была немного неясной. Теперь, чтобы уточнить мою цель:
Я хочу создать хранимую процедуру Postgres, которая будет принимать два входных параметра. Один будет список некоторых сумм, таких как, например, (100, 40.5, 76)
а другой будет список некоторых счетов ('01-2222-05','01-3333-04','01-4444-08')
, После этого я хочу использовать эти два списка цифр и символов и что-то с ними сделать. Например, я хочу взять каждую сумму из этого массива номеров и назначить ее для соответствующего счета.
Нечто подобное в Oracle будет выглядеть так:
SOME_PACKAGE.SOME_PROCEDURE (
789,
SYSDATE,
SIMPLEARRAYTYPE ('01-2222-05','01-3333-04','01-4444-08'),
NUMBER_TABLE (100,40.5,76),
'EUR',
1,
P_CODE,
P_MESSAGE);
Конечно, два типа SIMPLEARRAYTYPE
а также NUMBER_TABLE
определены ранее в БД.
2 ответа
Вам понравится эта новая функция Postgres 9.4:
unnest(anyarray, anyarray [, ...])
unnest()
с очень ожидаемой (по крайней мере, мной) способностью аккуратно размещать несколько массивов параллельно. Руководство:
разверните несколько массивов (возможно, разных типов) до набора строк. Это разрешено только в предложении FROM;
Это специальная реализация нового ROWS FROM
особенность
Ваша функция теперь может быть просто:
CREATE OR REPLACE FUNCTION multi_unnest(_some_id int
, _amounts numeric[]
, _invoices text[])
RETURNS TABLE (some_id int, amount numeric, invoice text) AS
$func$
SELECT _some_id, u.* FROM unnest(_amounts, _invoices) u;
$func$ LANGUAGE sql;
Вызов:
SELECT * FROM multi_unnest(123, '{100, 40.5, 76}'::numeric[]
, '{01-2222-05,01-3333-04,01-4444-08}'::text[]);
Конечно, простая форма может быть заменена простым SQL (без дополнительной функции):
SELECT 123 AS some_id, *
FROM unnest('{100, 40.5, 76}'::numeric[]
, '{01-2222-05,01-3333-04,01-4444-08}'::text[]) AS u(amount, invoice);
В более ранних версиях (Postgres 9.3-) вы можете использовать менее элегантную и менее безопасную форму:
SELECT 123 AS some_id
, unnest('{100, 40.5, 76}'::numeric[]) AS amount
, unnest('{01-2222-05,01-3333-04,01-4444-08}'::text[]) AS invoice;
Предостережения старой сокращенной формы: помимо того, что они нестандартны, имеют функцию возврата набора в SELECT
list, число возвращаемых строк будет наименьшим общим кратным для каждого числа массивов элементов (с неожиданными результатами для неравных чисел). Подробности в этих ответах:
- Параллельный unnest() и порядок сортировки в PostgreSQL
- Есть ли что-то вроде функции zip() в PostgreSQL, которая объединяет два массива?
Это поведение наконец-то было продезинфицировано с помощью Postgres 10. Несколько функций, возвращающих множество в SELECT
list производит строки в "lock-step" сейчас. Увидеть:
Массивы объявляются путем добавления []
к базовому типу данных. Вы объявляете их как параметр так же, как вы объявляете обычные параметры:
Следующая функция принимает массив целых чисел и массив строк и возвращает некоторый фиктивный текст:
create function array_demo(p_data integer[], p_invoices text[])
returns text
as
$$
select p_data[1] || ' => ' || p_invoices[1];
$$
language sql;
select array_demo(array[1,2,3], array['one', 'two', 'three']);
Демонстрация SQLFiddle: http://sqlfiddle.com/