postgres数组到列的数组

postgres array of arrays to columns

我的样本 table

Table_A
id integer
arr varchar(20) []

示例数据

id.         arr
1.    {{'a', 'b', 'c'}, {'d', 'test1', 'sample1'}}
2.    {{'sample2', sample3, sample4'}}
3.     null
4.    {{'sample6', 'sample7', 'test done'}}

我想 select 将数据设为:

id.     col1.       col2          col3  
1       'a'         'b'.          'c'
1.      'd'.       'test1'.      'sample1'
2.      'sample2'  'sample3'.    'sample4'
3.      null        null          null
4.     'sample6'.  'sample7'.    'test done'

如果not null,数据保证在数组中有 5 个元素。为方便起见,上面的示例数据包含 3 个元素。 这是一个相当大的 table,会随着时间的推移而增长。 现在我正在使用 unnest 然后 row_number() over () 然后用 id 加入它们。 有没有更好的方法呢

只有一种选择 - 用 Perl、Python 或 PLpgSQL 等 PL 语言编写过程代码。 Perl 或 Python 中的代码将更加动态(您不需要特殊类型),PLp​​gSQL 中的代码易于编写。对于大型数组,过程代码可能会更快。

CREATE OR REPLACE FUNCTION unnest_to_columns3(a text[])
RETURNS TABLE(col1 text, col2 text, col3 text)
AS $$
DECLARE r text[];
BEGIN
  FOREACH r SLICE 1 IN ARRAY a 
  LOOP
    col1 := r[1]; col2 := r[2]; col3 := r[3];
    RETURN NEXT;
  END LOOP;
END
$$ LANGUAGE plpgsql;

postgres=# SELECT * FROM unnest_to_columns3('{{a,b,c},{Ahoj,Nazdar,Servus}}');
+------+--------+--------+
| col1 |  col2  |  col3  |
+------+--------+--------+
| a    | b      | c      |
| Ahoj | Nazdar | Servus |
+------+--------+--------+
(2 rows)

注意:PostgreSQL 没有数组的数组——它只有多维数组。

记录数组比多维数组更实用。这种类型的关系和数组之间有简单的转换。

create table foo(v1 text, v2 text, v3 text);
insert into foo values('ahoj','nazdar','servus');
insert into foo values('hi','greating',null);

postgres=# select array_agg(foo) from foo;
+-------------------------------------------+
|                 array_agg                 |
+-------------------------------------------+
| {"(ahoj,nazdar,servus)","(hi,greating,)"} |
+-------------------------------------------+
(1 row)

postgres=# select * from unnest('{"(ahoj,nazdar,servus)","(hi,greating,)"}'::foo[]);
+------+----------+--------+
|  v1  |    v2    |   v3   |
+------+----------+--------+
| ahoj | nazdar   | servus |
| hi   | greating | ∅      |
+------+----------+--------+
(2 rows)

重要说明 - 关系 (table) 不是数组,数组也不是关系 (table)。

unnest() 对于常规多维数组有问题,它扩展了所有维度的所有元素,而不仅仅是第一个。因此,这些类型无法完成此操作。

一种可能的解决方法是将数组转换为 JSON 数组。对于 JSON 个数组,这不是问题:

demo:db<>fiddle

SELECT
    id,
    elems ->> 0 AS col1,
    elems ->> 1 AS col2,
    elems ->> 2 AS col3
FROM
    table_a,
    json_array_elements(array_to_json(arr)) elems

json_array_elements() 扩展数组的第一个维度,因此子数组移动到它们的一行中。然后简单地通过他们的索引得到他们的元素。


上面的查询消除了 NULL 行,因为它使用逗号表示法(实际上,在这种情况下,它是 INNER JOIN LATERAL 的快捷方式)。这可以使用 LEFT OUTER JOIN LATERAL 来避免:

demo:db<>fiddle

SELECT
    id,
    elems ->> 0 AS col1,
    elems ->> 1 AS col2,
    elems ->> 2 AS col3
FROM
    table_a
LEFT JOIN LATERAL
    json_array_elements(array_to_json(arr)) elems ON TRUE