并行取消嵌套多个数组

Posted

技术标签:

【中文标题】并行取消嵌套多个数组【英文标题】:Unnest multiple arrays in parallel 【发布时间】:2015-03-06 08:44:05 【问题描述】:

我的最后一个问题Passing an array to stored to 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);

当然,SIMPLEARRAYTYPENUMBER_TABLE 这两种类型在前面的 DB 中已经定义好了。

【问题讨论】:

究竟有什么不清楚的地方?如何调用这些函数?您可以使用数组构造函数 postgresql.org/docs/current/static/… 或者,您可以将它们的输入表示形式写入字符串(然后可选地使用强制转换)postgresql.org/docs/current/static/arrays.html#ARRAYS-IO 我不知道如何使用这些输入参数创建存储过程。 这也包含在您之前的问题中(例如 ***.com/questions/27708234/… )——您可以使用标准兼容的 <type> ARRAY 或 PostgreSQL 特定的 <type>[] 语法。 postgresql.org/docs/current/static/… 【参考方案1】:

通过将[] 添加到基本数据类型来声明数组。将它们声明为参数的方式与声明常规参数的方式相同:

以下函数接受整数数组和字符串数组,并返回一些虚拟文本:

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

【讨论】:

对不起,我的错,没关系。你可以在文本数组上使用 FOREACH 吗? 我可以在 Postgres 中对文本数组使用 FOREACH 吗? @Maki:如果一切都失败了,请阅读手册:postgresql.org/docs/current/static/…【参考方案2】:

你会喜欢 Postgres 9.4的这个新功能:

<b>unnest(anyarray, anyarray [, ...])</b>

unnest() 具有非常期待(至少在我看来)能够并行干净地取消嵌套多个数组的能力。 The manual:

将多个数组(可能是不同类型的)扩展为一组行。这只允许在 FROM 子句中;

这是新的ROWS FROM feature 的特殊实现。

你的函数现在可以是:

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[]);

当然,简单的形式也可以换成plain 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 列表中设置返回函数是不标准的,返回的行数将是每个数组元素数的最小公倍数(结果令人惊讶不等数)。这些相关答案中的详细信息:

Parallel unnest() and sort order in PostgreSQL Is there something like a zip() function in PostgreSQL that combines two arrays?

这种行为终于被 Postgres 10 清除了。 SELECT 列表中的多个集合返回函数现在以“锁步”方式生成行。见:

What is the expected behaviour for multiple set-returning functions in SELECT clause?

【讨论】:

文档中关于“rows from”语法的文档有点混乱,没有示例。仅供参考,select * from rows from(unnest('1,2,3'::integer[]), unnest('4,5,6'::integer[]), unnest('7,8'::integer[])) u(a, b, c); 将演示基本用法——“rows from”构造返回一个可在 from 子句中使用的表。

以上是关于并行取消嵌套多个数组的主要内容,如果未能解决你的问题,请参考以下文章

BigQuery - 如何取消嵌套多个数组,并从一列分配值?

如何在 BigQuery 中取消嵌套多个数组?

如何在存储为字符串的 bigquery 字段中取消嵌套多个数组?

在锁步中取消嵌套存储为文本的多个数组列

在 Join PostgreSQL 中取消嵌套数组

将数组数组取消嵌套到 plpgsql 中的简单数组