在视图上使用 'instead of' 触发器为 jsonb 数组中的每个元素插入
insert for each element in jsonb array with 'instead of' trigger on a view
我正在使用视图将相关行报告为数组。在视图上插入带有 instead of insert
触发器的行会很方便。要插入的行将需要使用相关 table.
中的键构造一个 json 对象
我目前不完整的实施需要where task in JSONB_ARRAY
。不知道可不可以。
除了主 ID 列为 vid
的 visit
table,我还有
task
table 拉取。
| task | sections |
+--------+-------------------------+
|task_A | ["section1","section2"] |
|task_B | ["part1", "part2" ] |
和一个 visit_task
table 来填充
| vid | task | measures |
+-----+--------+------------------------------------------------+
| 1 | task_C | ["level1": "value added later","level2": null] |
| 1 | task_E | ["q1": null,"q2": null] |
想要:
insert into vt_view (vid,tasks) values (1,'["task_A","task_B"]::jsonb)
实际做:
insert into visit_task (vid,task,measures)
values (1,'task_A','{"section1": null, "section2": null}'::jsonb);
insert into visit_task (vid,task,measures)
values (1,'task_B','{"part1": null, "part2": null}'::jsonb);
当前不完整的触发器解决方案摘录:
insert into visit_task from
select
NEW.vid as vid,
NEW.task as task,
-- *MAGIC* to create json object; measures list becomes object with null vals
row_to_json(_) from (select json_object(t.measures, 'null')) as measures
-- /MAGIC
from task t
-- *MAGIC* where we only grab the tasks within the array NEW.tasks
where t.task in (select * from NEW.tasks)
-- /MAGIC
不幸的是,服务器不知道如何处理 with/in MAGIC 标志。我也不会。
为了使任务更容易,创建一个辅助函数以将 sections
扩展为所需格式:
create or replace function expand_sections(jsonb)
returns jsonb language sql as $$
select jsonb_object_agg(e, null)
from jsonb_array_elements_text() e
$$;
-- test the function:
select task, expand_sections(sections)
from task;
task | expand_sections
--------+--------------------------------------
task_A | {"section1": null, "section2": null}
task_B | {"part1": null, "part2": null}
(2 rows)
使用触发函数中的函数:
create or replace function trigger_instead_on_vt_view()
returns trigger language plpgsql as $$
begin
insert into visit_task
select vid, task, expand_sections(sections)
from (
select new.vid, task
from jsonb_array_elements_text(new.tasks) task
) sub
join task using(task);
return null;
end $$;
create trigger trigger_instead_on_vt_view
instead of insert on vt_view
for each row execute procedure trigger_instead_on_vt_view();
insert into vt_view (vid,tasks) values (1,'["task_A","task_B"]'::jsonb);
select * from visit_task;
vid | task | measures
-----+--------+--------------------------------------
1 | task_A | {"section1": null, "section2": null}
1 | task_B | {"part1": null, "part2": null}
(2 rows)
如果您不想创建辅助函数,请使用此变体:
create or replace function trigger_instead_on_vt_view()
returns trigger language plpgsql as $$
begin
insert into visit_task
select vid, task, measures
from (
select new.vid, task
from jsonb_array_elements_text(new.tasks) task
) s
join (
select task, jsonb_object_agg(e, null) measures
from task, jsonb_array_elements_text(sections) e
group by 1
) t
using (task);
return null;
end $$;
我正在使用视图将相关行报告为数组。在视图上插入带有 instead of insert
触发器的行会很方便。要插入的行将需要使用相关 table.
我目前不完整的实施需要where task in JSONB_ARRAY
。不知道可不可以。
除了主 ID 列为 vid
的 visit
table,我还有
task
table 拉取。
| task | sections |
+--------+-------------------------+
|task_A | ["section1","section2"] |
|task_B | ["part1", "part2" ] |
和一个 visit_task
table 来填充
| vid | task | measures |
+-----+--------+------------------------------------------------+
| 1 | task_C | ["level1": "value added later","level2": null] |
| 1 | task_E | ["q1": null,"q2": null] |
想要:
insert into vt_view (vid,tasks) values (1,'["task_A","task_B"]::jsonb)
实际做:
insert into visit_task (vid,task,measures)
values (1,'task_A','{"section1": null, "section2": null}'::jsonb);
insert into visit_task (vid,task,measures)
values (1,'task_B','{"part1": null, "part2": null}'::jsonb);
当前不完整的触发器解决方案摘录:
insert into visit_task from
select
NEW.vid as vid,
NEW.task as task,
-- *MAGIC* to create json object; measures list becomes object with null vals
row_to_json(_) from (select json_object(t.measures, 'null')) as measures
-- /MAGIC
from task t
-- *MAGIC* where we only grab the tasks within the array NEW.tasks
where t.task in (select * from NEW.tasks)
-- /MAGIC
不幸的是,服务器不知道如何处理 with/in MAGIC 标志。我也不会。
为了使任务更容易,创建一个辅助函数以将 sections
扩展为所需格式:
create or replace function expand_sections(jsonb)
returns jsonb language sql as $$
select jsonb_object_agg(e, null)
from jsonb_array_elements_text() e
$$;
-- test the function:
select task, expand_sections(sections)
from task;
task | expand_sections
--------+--------------------------------------
task_A | {"section1": null, "section2": null}
task_B | {"part1": null, "part2": null}
(2 rows)
使用触发函数中的函数:
create or replace function trigger_instead_on_vt_view()
returns trigger language plpgsql as $$
begin
insert into visit_task
select vid, task, expand_sections(sections)
from (
select new.vid, task
from jsonb_array_elements_text(new.tasks) task
) sub
join task using(task);
return null;
end $$;
create trigger trigger_instead_on_vt_view
instead of insert on vt_view
for each row execute procedure trigger_instead_on_vt_view();
insert into vt_view (vid,tasks) values (1,'["task_A","task_B"]'::jsonb);
select * from visit_task;
vid | task | measures
-----+--------+--------------------------------------
1 | task_A | {"section1": null, "section2": null}
1 | task_B | {"part1": null, "part2": null}
(2 rows)
如果您不想创建辅助函数,请使用此变体:
create or replace function trigger_instead_on_vt_view()
returns trigger language plpgsql as $$
begin
insert into visit_task
select vid, task, measures
from (
select new.vid, task
from jsonb_array_elements_text(new.tasks) task
) s
join (
select task, jsonb_object_agg(e, null) measures
from task, jsonb_array_elements_text(sections) e
group by 1
) t
using (task);
return null;
end $$;