Массив JSON в одну строку в таблице SQL

#sql #postgresql

Вопрос:

У меня есть таблица в базе данных PostgreSQL.

 CREATE TABLE Receipts
(
    shop TEXT,
    receipt JSONB
);
 

С некоторыми данными в нем:

  shop |                    receipt                    
------ -----------------------------------------------
 ABC  | [["butter", 1, 3.45], ["potatoes", 1.5, 2.50]]
 XYZ  | [["butter", 1, 2.99], ["apples", 2.0, 1.80]]
 

receipt столбец содержит списки из 3-элементных списков.

Чего я пытаюсь добиться, так это написать SQL-запрос, который возвращает таблицу в виде

  shop |   product  | quantity |  price           
------ ------------ ---------- -----------
 ABC  |  'butter'  |    1     |  3.45
 ABC  | 'potatoes' |    1.5   |  2.50
 XYZ  |  'butter'  |    1     |  2.99
 XYZ  |  'apples'  |    2.0   |  1.80
 

Лучшее, что у меня есть на данный момент, — это

 # SELECT shop, jsonb_array_elements(receipt) FROM Receipts;
 shop |  jsonb_array_elements  
------ ------------------------
 ABC  | ["butter", 1, 3.45]
 ABC  | ["potatoes", 1.5, 2.5]
 XYZ  | ["butter", 1, 2.99]
 XYZ  | ["apples", 2.0, 1.8]
(4 rows)
 

но я застрял на том, чтобы не использовать внутренние массивы. Я пытался использовать jsonb_to_record , но, похоже, работает с объектами JSON, а не с массивами. Я буду признателен за ваш совет.

Ответ №1:

Вы были почти на месте, вам нужно только извлечь каждый элемент из массива, который вы извлекли, как вы можете видеть ниже

 with lines as (
  SELECT shop, jsonb_array_elements(receipt) as arr
  FROM receipts
)
select shop, arr->>0 as product, arr->>1 as quantity, arr->>2 as price
from lines;
 

дает результат:

  shop | product  | quantity | price 
------ ---------- ---------- -------
 ABC  | butter   | 1        | 3.45
 ABC  | potatoes | 1.5      | 2.50
 XYZ  | butter   | 1        | 2.99
 XYZ  | apples   | 2.0      | 1.80
 

Ответ №2:

Вы можете сделать это с помощью бокового соединения.

 select 
    r.shop, 
    l.ja->>0 product, 
    (l.ja->>1)::numeric quantity, 
    (l.ja->>2)::numeric price  
  from receipts r
  cross join lateral jsonb_array_elements(receipt) l(ja);