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

Мой последний вопрос Передача массива для хранения в 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 определены ранее в DB.


person Maki    schedule 08.01.2015    source источник
comment
Что именно непонятно? Как вызывать такие функции? Вы можете использовать конструкторы массивов postgresql. org / docs / current / static / или вы можете записать их входное представление в виде строки (затем при желании использовать приведение) postgresql.org/docs/current/static/arrays.html#ARRAYS-IO.   -  person pozs    schedule 08.01.2015
comment
Я не знаю, как создать хранимую процедуру с такими входными параметрами.   -  person Maki    schedule 08.01.2015
comment
Это также описано в ваших предыдущих вопросах (например, stackoverflow.com/questions/27708234/) - вы можете использовать стандартный совместимый <type> ARRAY или специальный <type>[] синтаксис PostgreSQL. postgresql.org/docs/current/static/   -  person pozs    schedule 08.01.2015


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


Это поведение было наконец исправлено с помощью Postgres 10. Несколько функций, возвращающих набор, в списке SELECT теперь производят строки в шаге блокировки. Видеть:

person Erwin Brandstetter    schedule 09.01.2015
comment
Документация для строк из синтаксиса в документации немного сбивает с толку, и здесь нет примера. Для справки select * from rows from(unnest('{1,2,3}'::integer[]), unnest('{4,5,6}'::integer[]), unnest('{7,8}'::integer[])) u(a, b, c); продемонстрирует базовое использование - строки из конструкции возвращают таблицу, которую можно использовать в предложении from. - person Simon D; 18.04.2018

Массивы объявляются путем добавления [] к базовому типу данных. Вы объявляете их как параметр так же, как объявляете обычные параметры:

Следующая функция принимает массив целых чисел и массив строк и возвращает фиктивный текст:

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/#!15/fdb8d/1

person a_horse_with_no_name    schedule 08.01.2015
comment
Извините, моя ошибка, все в порядке. Можно ли использовать FOREACH поверх текстового массива? - person Maki; 08.01.2015
comment
Могу ли я использовать FOREACH поверх текстового массива в Postgres? - person Maki; 08.01.2015
comment
@Maki: если ничего не помогает, прочтите руководство: postgresql.org/docs/current/static/ - person a_horse_with_no_name; 08.01.2015