仅当存在一对值时,Postgres 才会对 json 中的值求和

Postgres sum values from json only if pair of values exist

我的 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" 元素,但在上面的示例中显然不是这种情况。我只想计算这对值的差值,而忽略任何没有对应输出到输入的值。我该怎么做?

下面是我用来获取时差的

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

我不确定你的 json_column 属性 - 你需要按它分组以避免行之间的值混合,所以我将它包含在 CTE 部分的 window 聚合中。但是你的结果中没有它,所以我在最后的 qry 中也跳过了它。简而言之 - 您可以检查订单号是否为偶数且等于最大订单号,然后跳过它:

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)