UNNEST 复合数组到 Postgres 中的行和列
UNNEST a composite array into rows and columns in Postgres
Postgres 11.7.
我正在尝试解压缩一个数组,其中每个项目都有多个元素,但似乎无法获得正确的语法。我希望有人能指出我所缺少的。这是一个例子:
select
unnest(array[
('Red Large Special', 1),
('Blue Small', 5),
('Green Medium Special', 87)
]) as item_list
这就是我想要的:
item_name item_id
Red Large Special 1
Blue Small 5
Green Medium Special 87
这是我得到的:
base_strings
("Red Large Special",1)
("Blue Small",5)
("Green Medium Special",87)
我认为我需要列规范列表,如下所示:
select * from
unnest(array[
('Red Large Special', 1),
('Blue Small', 5),
('Green Medium Special', 87)
]) AS item_list(item_name citext, item_id int4)
我得到的是:
ERROR: function return row and query-specified return row do not match
DETAIL: Returned type unknown at ordinal position 1, but query expects citext. (Line 9)
如果我正式声明一个自定义的复合类型,我就能让它工作:
CREATE TYPE item_details AS (
item_name citext,
item_id int4);
select * from
unnest(array[
('Red Large Special', 1),
('Blue Small', 5),
('Green Medium Special', 87)
]::item_details[]) as item_list
这是对的:
item_name item_id
Red Large Special 1
Blue Small 5
Green Medium Special 87
有什么方法可以在不 声明类型的情况下获得相同的结果?我正在寻找可以定义类型 on-the-fly 的解决方案。我很确定我过去在 Postgres 中做过这个,但也许是 JSONB?
我查阅了有关 table 返回表达式的精美文档,但无法理解。那里没有真正的例子,我无法从语法摘要中推断出来。
https://www.postgresql.org/docs/current/queries-table-expressions.html
Follow-up
阻止我追逐自己尾巴的两个很好的答案。在这种情况下,任务是向多个客户端开放一些功能,所以我可能最好使用 JSON 而不是 Postgres-specific 数组语法。 @a_horse_with_no_name 引导我找到这种代码,从 JSON text:
开始
with expanded_data AS (
select *
from json_to_recordset(
'[
{"base_text":"Red Large Special","base_id":1},
{"base_text":"Blue Small","base_id":5},
{"base_text":"Green Medium Special","base_id":87}
]')
AS unpacked (base_text citext, base_id citext)
)
select base_text,
base_id
from expanded_data
我能想到的一种方法是将其转换为 jsonb 数组:
select item ->> 'f1' as item_name,
(item ->> 'f2')::int as item_id
from jsonb_array_elements(to_jsonb(array[
('Red Large Special', 1),
('Blue Small', 5),
('Green Medium Special', 87)
])) t(item)
因为字符串常量实际上有 unknown
类型,所以您需要明确指定所需的类型:
# select * from
unnest(array[
('Red Large Special'::citext, 1),
('Blue Small'::citext, 5),
('Green Medium Special'::citext, 87)
]) AS item_list(item_name citext, item_id int4);
┌──────────────────────┬─────────┐
│ item_name │ item_id │
├──────────────────────┼─────────┤
│ Red Large Special │ 1 │
│ Blue Small │ 5 │
│ Green Medium Special │ 87 │
└──────────────────────┴─────────┘
Postgres 11.7.
我正在尝试解压缩一个数组,其中每个项目都有多个元素,但似乎无法获得正确的语法。我希望有人能指出我所缺少的。这是一个例子:
select
unnest(array[
('Red Large Special', 1),
('Blue Small', 5),
('Green Medium Special', 87)
]) as item_list
这就是我想要的:
item_name item_id
Red Large Special 1
Blue Small 5
Green Medium Special 87
这是我得到的:
base_strings
("Red Large Special",1)
("Blue Small",5)
("Green Medium Special",87)
我认为我需要列规范列表,如下所示:
select * from
unnest(array[
('Red Large Special', 1),
('Blue Small', 5),
('Green Medium Special', 87)
]) AS item_list(item_name citext, item_id int4)
我得到的是:
ERROR: function return row and query-specified return row do not match
DETAIL: Returned type unknown at ordinal position 1, but query expects citext. (Line 9)
如果我正式声明一个自定义的复合类型,我就能让它工作:
CREATE TYPE item_details AS (
item_name citext,
item_id int4);
select * from
unnest(array[
('Red Large Special', 1),
('Blue Small', 5),
('Green Medium Special', 87)
]::item_details[]) as item_list
这是对的:
item_name item_id
Red Large Special 1
Blue Small 5
Green Medium Special 87
有什么方法可以在不 声明类型的情况下获得相同的结果?我正在寻找可以定义类型 on-the-fly 的解决方案。我很确定我过去在 Postgres 中做过这个,但也许是 JSONB?
我查阅了有关 table 返回表达式的精美文档,但无法理解。那里没有真正的例子,我无法从语法摘要中推断出来。
https://www.postgresql.org/docs/current/queries-table-expressions.html
Follow-up
阻止我追逐自己尾巴的两个很好的答案。在这种情况下,任务是向多个客户端开放一些功能,所以我可能最好使用 JSON 而不是 Postgres-specific 数组语法。 @a_horse_with_no_name 引导我找到这种代码,从 JSON text:
开始with expanded_data AS (
select *
from json_to_recordset(
'[
{"base_text":"Red Large Special","base_id":1},
{"base_text":"Blue Small","base_id":5},
{"base_text":"Green Medium Special","base_id":87}
]')
AS unpacked (base_text citext, base_id citext)
)
select base_text,
base_id
from expanded_data
我能想到的一种方法是将其转换为 jsonb 数组:
select item ->> 'f1' as item_name,
(item ->> 'f2')::int as item_id
from jsonb_array_elements(to_jsonb(array[
('Red Large Special', 1),
('Blue Small', 5),
('Green Medium Special', 87)
])) t(item)
因为字符串常量实际上有 unknown
类型,所以您需要明确指定所需的类型:
# select * from
unnest(array[
('Red Large Special'::citext, 1),
('Blue Small'::citext, 5),
('Green Medium Special'::citext, 87)
]) AS item_list(item_name citext, item_id int4);
┌──────────────────────┬─────────┐
│ item_name │ item_id │
├──────────────────────┼─────────┤
│ Red Large Special │ 1 │
│ Blue Small │ 5 │
│ Green Medium Special │ 87 │
└──────────────────────┴─────────┘