UNNEST составной массив в строки и столбцы в Postgres - PullRequest
1 голос
/ 08 мая 2020

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

Есть ли способ получить такой же результат без объявления типа? Я ищу решение, в котором я могу определять тип на лету. Я почти уверен, что раньше делал это в Postgres, но, может быть, это было с JSONB?

Я проконсультировался с «Fine Documentation» по выражениям, возвращающим таблицы, но не смог следовать за ней. На самом деле там нет примера, я не могу экстраполировать из грамматического резюме.

https://www.postgresql.org/docs/current/queries-table-expressions.html

Продолжение

Два отличные ответы, которые не дают мне гнаться за собственным хвостом. В этом случае задача состоит в том, чтобы открыть некоторые функции для нескольких клиентов, поэтому мне, вероятно, лучше использовать JSON, чем синтаксис массива Postgres -specifi c. @a_horse_with_no_name приводит меня к такому коду, начиная с JSON текста:

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

Ответы [ 2 ]

2 голосов
/ 08 мая 2020

Поскольку строковые константы на самом деле имеют тип 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 │
└──────────────────────┴─────────┘
2 голосов
/ 08 мая 2020

Один из способов, который я могу придумать, - это преобразовать его в массив 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)
...