snippetsqlMinor
How to sum nested values from a JSON array based on conditions
Viewed 0 times
conditionshowarrayjsonnestedbasedsumvaluesfrom
Problem
I have a table with 3 columns in Postgres 14.2:
And these rules:
-
name (john) and name_adds (doe) or both value is (john)
-
column
format 1:
format 2:
-
If (name = name_adds) sum default -> value_1
-
If (name != name_adds) sum non_default -> value_1
How can I sum format 1 or 2 from point 2. based on the rules in point 3. and 4.?
Example table:
Expected result:
I tried a query in this online demo, but didn't manage to get the expected result.
name, name_adds, aditional.And these rules:
-
name and name_adds can be filled with the same value or not. Example:name (john) and name_adds (doe) or both value is (john)
-
column
additional has one of two formats:format 1:
{"default":[{"value_1": 100, "value_2": 0.1},{"value_1": 200, "value_2": 0.2}], "non_default":[{"value_1": 200, "value_2": 0.1}, {"value_1": 400, "value_2": 0.1}]}format 2:
[{"value_1": 10,"value_2": 11},{"value_1": 1,"value_2": 19}-
If (name = name_adds) sum default -> value_1
-
If (name != name_adds) sum non_default -> value_1
How can I sum format 1 or 2 from point 2. based on the rules in point 3. and 4.?
Example table:
name name_adds additional
---------------------------------------------------------------
john john {"default":[{"value_1": 100, "value_2": 0.1},
{"value_1": 200, "value_2": 0.2}],"non_default":
[{"value_1": 200, "value_2": 0.1}, {"value_1": 400,
"value_2": 0.1}]}
john doe {"default":[{"value_1": 100, "value_2": 0.1},
{"value_1": 200, "value_2": 0.2}],"non_default":
[{"value_1": 200, "value_2": 0.1}, {"value_1": 400,
"value_2": 0.1}]}
downy downy [{"value_1": 10, "value_2": 11},{"value_1": 1,"value_2": 19}]
downy dan [{"value_1": 10, "value_2": 11},{"value_1": 1,"value_2": 19}]Expected result:
name name_adds sum_result
---------------------------------------------------------------
john john 300
john doe 600
downy downy 11
downy dan 11I tried a query in this online demo, but didn't manage to get the expected result.
Solution
SELECT a.name, a.name_adds, sub.*
FROM test_json a
CROSS JOIN LATERAL (
SELECT sum((obj ->> 'value_1')::int) AS sum_result -- or numeric?
FROM json_array_elements(COALESCE(CASE WHEN name = name_adds
THEN additional::json -> 'default'
ELSE additional::json -> 'non_default' END
, additional::json)) obj
) sub;db<>fiddle here
This relies on
additional::json -> 'default' (or 'non_default', respectively) being NULL in case of "format 2", in which case we take additional::json directly for "format 1" using COALESCE.Then unnest with
json_array_elements(), and sum extracted value_1.The column
additional should be type json (or jsonb) to begin with.Chances are, you would be much better off with a normalized relational design replacing that highly regular JSON column completely.
Code Snippets
SELECT a.name, a.name_adds, sub.*
FROM test_json a
CROSS JOIN LATERAL (
SELECT sum((obj ->> 'value_1')::int) AS sum_result -- or numeric?
FROM json_array_elements(COALESCE(CASE WHEN name = name_adds
THEN additional::json -> 'default'
ELSE additional::json -> 'non_default' END
, additional::json)) obj
) sub;Context
StackExchange Database Administrators Q#313252, answer score: 4
Revisions (0)
No revisions yet.