Postgres сумма значений из JSON, только если существует пара значений - PullRequest
0 голосов
/ 10 мая 2018

Мое поле json выглядит примерно так

{
"Ui": [
    {
        "element": "TG1",
        "mention": "in",
        "time": 123
    },
    {
        "element": "TG1",
        "mention": "out",
        "time": 125
    },        
    { "element": "TG2",
        "mention": "in",
        "time": 251
    },
    {
        "element": "TG2",
        "mention": "out",
        "time": 259
    },        
    { "element": "TG2",
        "mention": "in",
        "time": 251
    }
]
 }

Я пытаюсь получить сумму разницы времени на элемент, как показано ниже

| element  |   Timespent   |
|  TG1     |     2         |
|  TG2     |     8         |

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

Ниже приведено то, что я использую, чтобы получить времяразница

select element, sum(time) as time_spent
from my_table
cross join lateral (
  select
    value->>'element' as element,
    case value->>'mention' when 'in' then -(value->>'time')::numeric else (value->>'time')::numeric end as time
  from json_array_elements(json_column->'Ui')) as elements
group by 1
order by 1

1 Ответ

0 голосов
/ 11 мая 2018

Я не был уверен в вашем атрибуте json_column - вам нужно сгруппировать его, чтобы не смешивать значения между строками, поэтому я включил его в агрегаты окон в части CTE. Но у вас его нет в ваших результатах, поэтому я пропустил его и в последнем отчете. Вкратце - вы можете проверить, является ли номер заказа четным и равным максимальному номеру заказа, а затем просто пропустить его:

select json_column
, e->>'element' element
, case when
 mod(lag(i) over (partition by json_column::text ,e->>'element' order by i),2) = 0
 and
 max(i) over (partition by json_column::text ,e->>'element') = i
then true else false end "skip"
, case when e->>'mention' = 'in' then -(e->>'time')::int else (e->>'time')::int end times
from my_table, json_array_elements(json_column->'Ui') with ordinality o(e,i)
)
select element, sum (times)
from logic
where not skip
group by element
;
 element | sum
---------+-----
 TG1     |   2
 TG2     |   8
(2 rows)
...