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 中的代码将更加动态(您不需要特殊类型),PLpgSQL 中的代码易于编写。对于大型数组,过程代码可能会更快。
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 个数组,这不是问题:
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
来避免:
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
我的样本 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 中的代码将更加动态(您不需要特殊类型),PLpgSQL 中的代码易于编写。对于大型数组,过程代码可能会更快。
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 个数组,这不是问题:
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
来避免:
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