PL/pgSQL 逐字段求和两个jsons或两行
PL/pgSQL Sum two jsons or two rows field by field
我花了好几个小时来寻找我的问题的答案,但我没有:
我想将某些行(具有相同日期和 'name' 值)的所有值相加到另一行中,即 'aggregation one'.
为此,我 select 想要的行,通过 date/name 对所有行执行我的循环,然后在行字段上执行最后一个循环以逐个对字段求和:
DO $code$
DECLARE
date_trunc_by_hour record;
row_for_hour record;
field_of_row_for_hour record;
aggreged metrics.bot%ROWTYPE;
first boolean := true;
BEGIN
--boucle par heure, loop by hour
FOR date_trunc_by_hour IN
SELECT date_trunc('hour',date) as date_trunc
FROM metrics.bot
where aggrege = false
group by date_trunc
LOOP
RAISE INFO 'Recherche pour la date : %', date_trunc_by_hour.date_trunc;
--boucle par row dans l'heure, loop on each row for the hour selected
first := true ;
FOR row_for_hour IN
SELECT *
FROM metrics.bot
where date_trunc('hour',date) = date_trunc_by_hour.date_trunc
LOOP
IF first = true
THEN
aggreged := row_for_hour; -- if it's the first row, i take the values of this row to add ones of the others rows after
RAISE INFO '%', aggreged;
first = false;
ELSE -- if its not the first, i want to add values field by field to the first one
FOR field_of_row_for_hour IN select * from json_each(row_to_json(row_for_hour))
LOOP
-- Here i would like for each field of each row in the loop, to add incoming row value to aggreged value, value can be a json
END LOOP;
END IF;
END LOOP;
END LOOP;
END $code$;
例如,前两行有相同的bot/date对,应该给第三对:
===== ===================== ========= ========= ===== ============================ ==========
BOT DATE PROCESS INSERT MAJ ERRORS aggreged
===== ===================== ========= ========= ===== ============================ ==========
1 2019-02-12 17:00:00 scan 2 5 {"société":1} false
1 2019-02-12 17:00:00 scan 4 7 {"société":1,"enchere":1} false
1 2019-02-12 17:00:00 scan 6 12 {"enchere":1, "société":2} true
===== ===================== ========= ========= ===== ============================ ==========
我将在删除第 1 行和第 2 行之前插入 table。
在我的记忆中,我曾经用 json 转换解决过这个问题,但我不记得是如何解决的。
感谢您的帮助
您需要一个对整数属性求和的自定义聚合:
create or replace function jsonb_sum_attributes(jsonb, jsonb)
returns jsonb language sql as $$
select jsonb_object_agg(key, sum)
from (
select key, sum(value::int)
from (
select *
from jsonb_each_text()
union all
select *
from jsonb_each_text()
) s
group by key
) s
$$;
create aggregate jsonb_sum_attributes_agg(jsonb)
(
sfunc = 'jsonb_sum_attributes',
stype = jsonb,
initcond = '{}'
);
查询:
select bot, date, process, insert, maj, errors, aggreged
from bot
union
select bot, date, process, sum(insert), sum(maj), jsonb_sum_attributes_agg(errors), true
from bot
group by bot, date, process
order by bot, date, process, aggreged
bot | date | process | insert | maj | errors | aggreged
-----+---------------------+---------+--------+-----+------------------------------+----------
1 | 2019-02-12 17:00:00 | scan | 2 | 5 | {"société": 1} | f
1 | 2019-02-12 17:00:00 | scan | 4 | 7 | {"enchere": 1, "société": 1} | f
1 | 2019-02-12 17:00:00 | scan | 6 | 12 | {"enchere": 1, "société": 2} | t
(3 rows)
我花了好几个小时来寻找我的问题的答案,但我没有:
我想将某些行(具有相同日期和 'name' 值)的所有值相加到另一行中,即 'aggregation one'.
为此,我 select 想要的行,通过 date/name 对所有行执行我的循环,然后在行字段上执行最后一个循环以逐个对字段求和:
DO $code$
DECLARE
date_trunc_by_hour record;
row_for_hour record;
field_of_row_for_hour record;
aggreged metrics.bot%ROWTYPE;
first boolean := true;
BEGIN
--boucle par heure, loop by hour
FOR date_trunc_by_hour IN
SELECT date_trunc('hour',date) as date_trunc
FROM metrics.bot
where aggrege = false
group by date_trunc
LOOP
RAISE INFO 'Recherche pour la date : %', date_trunc_by_hour.date_trunc;
--boucle par row dans l'heure, loop on each row for the hour selected
first := true ;
FOR row_for_hour IN
SELECT *
FROM metrics.bot
where date_trunc('hour',date) = date_trunc_by_hour.date_trunc
LOOP
IF first = true
THEN
aggreged := row_for_hour; -- if it's the first row, i take the values of this row to add ones of the others rows after
RAISE INFO '%', aggreged;
first = false;
ELSE -- if its not the first, i want to add values field by field to the first one
FOR field_of_row_for_hour IN select * from json_each(row_to_json(row_for_hour))
LOOP
-- Here i would like for each field of each row in the loop, to add incoming row value to aggreged value, value can be a json
END LOOP;
END IF;
END LOOP;
END LOOP;
END $code$;
例如,前两行有相同的bot/date对,应该给第三对:
===== ===================== ========= ========= ===== ============================ ==========
BOT DATE PROCESS INSERT MAJ ERRORS aggreged
===== ===================== ========= ========= ===== ============================ ==========
1 2019-02-12 17:00:00 scan 2 5 {"société":1} false
1 2019-02-12 17:00:00 scan 4 7 {"société":1,"enchere":1} false
1 2019-02-12 17:00:00 scan 6 12 {"enchere":1, "société":2} true
===== ===================== ========= ========= ===== ============================ ==========
我将在删除第 1 行和第 2 行之前插入 table。
在我的记忆中,我曾经用 json 转换解决过这个问题,但我不记得是如何解决的。
感谢您的帮助
您需要一个对整数属性求和的自定义聚合:
create or replace function jsonb_sum_attributes(jsonb, jsonb)
returns jsonb language sql as $$
select jsonb_object_agg(key, sum)
from (
select key, sum(value::int)
from (
select *
from jsonb_each_text()
union all
select *
from jsonb_each_text()
) s
group by key
) s
$$;
create aggregate jsonb_sum_attributes_agg(jsonb)
(
sfunc = 'jsonb_sum_attributes',
stype = jsonb,
initcond = '{}'
);
查询:
select bot, date, process, insert, maj, errors, aggreged
from bot
union
select bot, date, process, sum(insert), sum(maj), jsonb_sum_attributes_agg(errors), true
from bot
group by bot, date, process
order by bot, date, process, aggreged
bot | date | process | insert | maj | errors | aggreged
-----+---------------------+---------+--------+-----+------------------------------+----------
1 | 2019-02-12 17:00:00 | scan | 2 | 5 | {"société": 1} | f
1 | 2019-02-12 17:00:00 | scan | 4 | 7 | {"enchere": 1, "société": 1} | f
1 | 2019-02-12 17:00:00 | scan | 6 | 12 | {"enchere": 1, "société": 2} | t
(3 rows)