gpt4 book ai didi

postgresql - 使用 pl/pgsql 插入选择行

转载 作者:行者123 更新时间:2023-11-29 12:03:25 25 4
gpt4 key购买 nike

问题:有没有办法(也许是 pl/pgsql 函数方式?)使用在我的日志表中找到的值(即值“action”、“schema_name”、“table_name”、“column_name”、“data_type”(即列数据类型)和“new_val”?)。

正在记录的表和我需要运行 INSERT/UPDATE/或 DELETE 的表如下所示:

enter image description here

..日志表如下所示:

enter image description here

...4 个突出显示的日志条目应该像这样插入到表中:

enter image description here

...我正在尝试找到一种方法来在 ANOTHER DATABASE 表 上运行 INSERT/UPDATE/or DELETE(在名称/架构/等方面与正在记录的表相同)在日志表中选择特定的“usr”和“event_date”之后。

为了获得我想要的结果(仅针对 INSERT 语句 - 见下文)SQL 非常粗糙 (demo in SQL FIDDLE)。我很想知道是否还有其他方法......

INSERT INTO Engineering.Elective_Courses 
(gid, grade, class, student_id)
WITH
t1 AS
(Select new_val
From student.history
WHERE
column_name = 'gid'
AND
usr = 'Principal K.'
AND
(event_date >= '2017-01-26' AND event_date < '2017-01-29')),
t2 AS (Select new_val
From student.history
WHERE
column_name = 'grade'
AND
usr = 'Principal K.'
AND
(event_date >= '2017-01-26' AND event_date < '2017-01-29')),
t3 AS (Select new_val
From student.history
WHERE
column_name = 'class'
AND
usr = 'Principal K.'
AND
(event_date >= '2017-01-26' AND event_date < '2017-01-29')),
t4 AS (Select new_val
From student.history
WHERE
column_name = 'student_id'
AND
usr = 'Principal K.'
AND
(event_date >= '2017-01-26' AND event_date < '2017-01-29'))
select t1.new_val::int, t2.new_val, t3.new_val, t4.new_val::int
from t1,t2, t3, t4;

最佳答案

你必须使用 dynamic SQL .

此查询汇总了各个操作的数据:

select 
action, event_date, usr,
schema_name, table_name, pkey_id,
string_agg(quote_ident(column_name), ',' order by history_id) as cols,
-- string_agg(quote_literal(new_val), ',' order by history_id) as vals
-- correction:
string_agg(coalesce(quote_literal(new_val), 'null'), ',' order by history_id) as vals
from student.history
group by 1, 2, 3, 4, 5, 6;

action | event_date | usr | schema_name | table_name | pkey_id | cols | vals
--------+---------------------+--------------+-------------+------------------+---------+----------------------------+----------------------------
DELETE | 2017-01-28 12:20:03 | Ast. Dean J. | Engineering | Elective_Courses | 14 | grade |
INSERT | 2017-01-26 22:42:53 | Principal K. | Engineering | Elective_Courses | 12 | gid,grade,class,student_id | '12','B-','PYS7C','607752'
UPDATE | 2017-01-26 22:42:53 | Ast. Dean J. | Engineering | Elective_Courses | 13 | grade | 'C'
(3 rows)

为了更好的安全性,历史表应该有一个额外的唯一 Action ID 来区分例如。同一用户同时在同一张表上进行两次插入,尽管这种巧合不太可能。

该函数基于上述查询。它有一个参数,即历史表中 WHERE 子句的文本。它返回生成的查询。它还可以执行查询(在注释的代码段中)。

create or replace function restore_log(condition text)
returns setof text language plpgsql as $$
declare
relid regclass;
pkey text;
query text;
rec record;
begin
for rec in
execute format('
select
action, event_date, usr,
schema_name, table_name, pkey_id,
string_agg(quote_ident(column_name), '','' order by history_id) as cols,
string_agg(coalesce(quote_literal(new_val), ''null''), '','' order by history_id) as vals
from student.history
where %s
group by 1, 2, 3, 4, 5, 6',
condition)
loop
relid:= format('%s.%s', rec.schema_name, rec.table_name)::regclass;
pkey:= get_pkey_name(relid); -- see below
query:= case rec.action
when 'INSERT' then
format(
'insert into %s.%s (%s) values (%s)',
rec.schema_name, rec.table_name, rec.cols, rec.vals)
when 'UPDATE' then
format(
'update %s.%s set (%s) = (%s) where %s = %s',
rec.schema_name, rec.table_name, rec.cols, rec.vals, pkey, rec.pkey_id)
when 'DELETE' then
format(
'delete from %s.%s where %s = %s',
rec.schema_name, rec.table_name, pkey, rec.pkey_id)
else null end;
return next query;
-- if query not null then
-- execute(query);
-- end if;
end loop;
end $$;

使用示例:

select * from restore_log('true');

restore_log
-----------------------------------------------------------------------------------------------------------
delete from Engineering.Elective_Courses where gid = 14
insert into Engineering.Elective_Courses (gid,grade,class,student_id) values ('12','B-','PYS7C','607752')
update Engineering.Elective_Courses set (grade) = ('C') where gid = 13
(3 rows)


select * from restore_log($$
usr = 'Principal K.'
and event_date >= '2017-01-26'
and event_date < '2017-01-29'$$);

restore_log
-----------------------------------------------------------------------------------------------------------
insert into Engineering.Elective_Courses (gid,grade,class,student_id) values ('12','B-','PYS7C','607752')
(1 row)

查找给定表的单列主键的列名的函数(用于restore_log()):

create or replace function get_pkey_name(regclass)
returns name language sql as $$
select attname
from pg_constraint c
join pg_attribute a on attrelid = conrelid and attnum = conkey[1]
where conrelid = $1
and contype = 'p'
and cardinality(conkey) = 1
$$;

安全注意事项,基本上你应该使用 format('%I.%I, schema_name, table_name) 出于安全原因,但在这种情况下,由于使用大写字母,它会给出错误的结果在数据中。

关于postgresql - 使用 pl/pgsql 插入选择行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41904958/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com