PostgreSQL: How to SUM attributes including a JSONB field, and retain table shape?

北城以北 提交于 2019-12-12 04:05:55

问题


I am working with Postgres 9.4. I have a table with a JSONB field:

     Column      │         Type         │                             Modifiers
─────────────────┼──────────────────────┼────────────────────────────────────────────────────────────────────
 id              │ integer              │ not null default
 practice_id     │ character varying(6) │ not null
 date            │ date                 │ not null
 pct_id          │ character varying(3) │
 astro_pu_items  │ double precision     │ not null
 astro_pu_cost   │ double precision     │ not null
 star_pu         │ jsonb                │

I want to retrieve the summed values by date of various attributes, including anything in the JSONB array (which it is safe to assume has depth 1), and return the values in the same structure as in the original table.

This is the query I'm using right now:

SELECT date,
       SUM(total_list_size) AS total_list_size,
       json_object_agg(key, val)
FROM (
    SELECT date,
           SUM(total_list_size) AS total_list_size,
           key, SUM(value::numeric) val
    FROM frontend_practicelist p, jsonb_each_text(star_pu)
    GROUP BY date, key
    ) p
GROUP BY date
ORDER BY date;

It does not fail, and the JSON is presented as a dictionary which is how I want it. However, the summed value of total_list_size looks hugely too large. I think it must be being summed twice.

How can I get the correct summed value for total_list_size, while retaining the same shape results?


回答1:


The function jsonb_each_text() in the subquery causes the column total_list_size is replicated as many times as number of items in star_pu, so avg() shows a proper result.

To get one total_list_size for a date you can use a parallel subquery that accumulates the value independently.

select *
from (
    select date, json_object_agg(key, val) total_star_pu
    from (
        select date, key, sum(value::numeric) val
        from frontend_practicelist, jsonb_each_text(star_pu)
        group by date, key
        ) s
    group by date
    ) s
    join (
        select date, sum(total_list_size) total_list_size
        from frontend_practicelist
        group by date
        ) t
    using(date)
order by date;



回答2:


I've written a Postgres extension to sum jsons. Once you have it installed you can simply do:

select date, sum(total_size_list), jsonb_deep_sum(star_pu) from frontend_practicelist;


来源:https://stackoverflow.com/questions/35130870/postgresql-how-to-sum-attributes-including-a-jsonb-field-and-retain-table-shap

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!