распаковать все самые внешние ключи в объекте json в виде столбцов

#json #postgresql

#json #postgresql

Вопрос:

У меня есть postgres DB, вызываемая sales с помощью json-объекта, data содержащего около 100 внешних ключей, давайте назовем их k1,k2,k3..,k100 .

Я хочу написать запрос

 select * from sales some_function(data)
  

который просто возвращает что-то вроде

 k1    |  k2 | .. | k100
--------------------
"foo" | "bar" | .. | 2
"fizz"| "buzz"| .. | 10
  

т.е. просто распакуйте ключи как columnn, а их значения — как row.
Обратите внимание, k1,k2..k100 что это не их настоящее имя, поэтому я не могу сделать

data->> key цикл

Ответ №1:

Это невозможно. Одним из ограничений языка SQL является то, что все столбцы (и их типы данных) должны быть известны базе данных при разборе инструкции — то есть до ее фактического запуска.

Вам придется писать каждый из них отдельно:

 select data ->> 'k1' as k1, data ->> 'k2' as k2, ...
from sales
  

Один из способов упростить это — динамически генерировать представление, извлекая все ключи JSON из столбца, а затем используя динамический SQL для создания представления. Однако вам нужно будет заново создавать это представление каждый раз, когда меняется количество ключей.

Что-то вроде (не проверено!)

 do
$$
declare
  l_columns text;
  l_sql text;
begin
  select string_agg(distinct format('data ->> %L as %I', t.key, t.key), ', ')
    into l_columns
  from sales s
    cross join jsonb_each(s.data) as t(key, value);

  -- l_columns now contains something like: 
  -- data ->> 'k1' as k1, data ->> 'k2' as k2

  -- now create a view from that
  l_sql := 'create view sales_keys as select '||l_columns||' from sales';
  execute l_sql;
end;
$$
;
  

Вероятно, вы захотите добавить, например, столбцы первичного ключа в представление, чтобы вы могли сопоставить значения JSON с исходными строками.

Комментарии:

1. На самом деле я только что нашел json_each функцию в postgresql.org/docs/9.3/functions-json.html . Кажется, он выполняет свою работу (только по строкам).

2. @CutePoison: да, это тот, который я использовал для извлечения ключей для генерации динамического SQL. Кстати: вам не следует читать руководство для прекращенных версий Postgres. Прочитайте руководство для версии, которую вы фактически используете

3. Извините, я этого не видел. Я буду перезапускать этот скрипт каждый день, поэтому, полагаю, не составит труда воссоздать представление при изменении их ключей?

4. Я не думаю, что это будет проблемой. Получение отдельных ключей из большой таблицы может занять довольно много времени, хотя вы можете запланировать это создание на нерабочее время

5. Нет, это не так