postgresql - How to UPDATE a JSON column with a nested aggregation? - Stack Overflow

How do I write an UPDATE statement for a JSON column using a nested aggregation?I have two tables, job

How do I write an UPDATE statement for a JSON column using a nested aggregation?

I have two tables, jobs and job_statuses. Jobs has a rows with a group and status column and job_statuses has a statuses JSON column that contains a count of statuses for that group:

jobs

id group name status
1 2 foo running
1 2 bar done

How do I write an UPDATE statement for a JSON column using a nested aggregation?

I have two tables, jobs and job_statuses. Jobs has a rows with a group and status column and job_statuses has a statuses JSON column that contains a count of statuses for that group:

jobs

id group name status
1 2 foo running
1 2 bar done

job_statuses

group statuses
2 {"running": 1, "done": 1}

I want to be able to write an UPDATE to set statuses to for a given group. That is, update only one row at a time.

So far I've tried this with a CTE but I'm unsure of how to write the json_object_agg without getting a aggregate functions are not allowed in UPDATE error.

WITH status_agg AS (
  SELECT
    job.status as status,
    count(job.id) AS count 
  FROM
    job
  WHERE
    job.group = 2
  GROUP BY
    job.status
  ORDER BY
    job.status
)
UPDATE job_statuses
SET statuses = json_build_object(status_agg.status, status_agg.count)
FROM status_agg
WHERE job_statuses.group = 2;

What is the correct way to write this UPDATE?


Solution

As @Zegarek points out. I can just use a second CTE to remove the aggregation in the UPDATE statement.

WITH status_agg AS (
  SELECT
    platform.task.status as status,
    count(platform.task.id) AS count 
  FROM
    platform.task 
  WHERE
    platform.task.pipeline_id = 2
  GROUP BY
    platform.task.status
  ORDER BY
    platform.task.status
),
json_status AS (
  SELECT json_build_object(status, count) as result FROM status_agg
) 
UPDATE pipeline_stat
SET statuses = json_status.result
FROM json_status
WHERE pipeline_stat.id = 2;
Share Improve this question edited Mar 22 at 17:29 Aage Torleif asked Mar 22 at 17:09 Aage TorleifAage Torleif 2,0251 gold badge22 silver badges42 bronze badges 2
  • 1 You can add another CTE that does the second aggregation. – Zegarek Commented Mar 22 at 17:17
  • Oh? Yes this seems to work. Thank you, very simple solution. – Aage Torleif Commented Mar 22 at 17:27
Add a comment  | 

1 Answer 1

Reset to default 2
update job_statuses as target
set statuses=(select json_object_agg(status,count)
              from(select job.status as status
                        , count(job.id) as count 
                   from jobs as job
                   where job.group_ = target.group_
                   group by job.status
                   order by job.status) as s1)
where group_ = 2;

A scalar subquery above is another way you can handle this. Adding a CTE works too:
demo at db<>fiddle

with status_agg as (
  select job.status as status
       , count(job.id) as count 
  from jobs as job
  where job.group_ = 2
  group by job.status
  order by job.status
),status_agg_jsonb as(
  select json_object_agg(  status_agg.status
                         , status_agg.count) as v
  from status_agg)
update job_statuses
set statuses = status_agg_jsonb.v
from status_agg_jsonb
where job_statuses.group_ = 2;

Instead of plain json, consider jsonb.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744306765a4567751.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信