Развернуть несколько массивов параллельно

Мой последний вопрос Передача массива для хранения в 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, число возвращаемых строк будет наименьшим общим кратным для каждого числа массивов элементов (с неожиданными результатами для неравных чисел). Подробности в этих ответах:

Это поведение наконец-то было продезинфицировано с помощью 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/

Другие вопросы по тегам