Выберите значение JSON из набора результатов структуры EAV - PullRequest
0 голосов
/ 18 января 2019

Учитывая набор результатов, который находится в структуре EAV, такой как:

id   | attributeName  | stringValue | intValue  | BooleanValue
---------------------------------------------------------------
1       stringFoo            v1
1       stringFooList        v2   
1       stringFooList        v3
1       intFoo                           10
1       intFooList                       10
1       intFooList                       20
1       booleanFoo                                     true
1       booleanFooList                                 true 
1       booleanFooList                                 true

Как я могу выбрать все атрибуты и пару значений как одно значение в формате JSON / JSONB, что-то вроде:

{
    "stringFoo"         : "v1" , 
    "stringFooList"     : ["v2","v3"] ,
    "intFoo"            : 10 ,
    "intFooList"        : [10,20],
    "booleanFoo"        : true,
    "booleanFooList"    : [true,true]
}

Если для атрибута существует несколько значений атрибута, например stringFooList, он будет отформатирован как массив JSON.

Я использую PostgreSQL 9,6

Ответы [ 2 ]

0 голосов
/ 18 января 2019

@a_horse_with_no_name ответ дает мне хорошее начало. Я расширяю его / ее ответ и подхожу к следующему запросу так, чтобы элементы в массиве JSON имели тот же тип данных, который определен в PostgreSQL.

select id, jsonb_object_agg(att, 
    case 
      when strval is not null then strval
      when intvalue is not null then intvalue
      else boolVal
     end 
    )
from (
  select id, 
         attributename as att,  
         case when count(*) > 1 then 
            jsonb_agg(stringvalue) filter (where stringvalue is not null) 
         else 
            to_jsonb(min(stringvalue) filter (where stringvalue is not null))     
         end as strVal, 

         case when count(*) > 1 then 
            jsonb_agg(intvalue) filter (where intvalue is not null) 
         else 
            to_jsonb(min(intvalue) filter (where intvalue is not null))     
         end as intvalue, 

         case when count(*) > 1 then 
            jsonb_agg(booleanvalue) filter (where booleanvalue is not null) 
         else 
            to_jsonb(bool_and(booleanvalue) filter (where booleanvalue is not null))     
         end as boolVal
  from eav
  group by id, attributename
) t
group by id;
0 голосов
/ 18 января 2019

Вы можете сделать что-то вроде этого:

select id, jsonb_object_agg(att, value)
from (
  select id, 
         attributename as att, 
         case 
           when count(*) > 1 then 
               jsonb_agg(coalesce(stringvalue,intvalue::text,booleanvalue::text)) 
           else 
              to_jsonb(min(coalesce(stringvalue,intvalue::text,booleanvalue::text)))
         end as value
  from eav
  group by id, attributename
) t
group by id;

Внутренний выбор объединяет несколько значений в массив JSON, отдельные значения - в скалярные значения JSON. И тогда внешний запрос строит единственное значение JSON из всех строк.

Онлайн пример: https://rextester.com/TLCRN79815

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...