在 PostgreSQL 函数中基于 JSON 更新表
Posted
技术标签:
【中文标题】在 PostgreSQL 函数中基于 JSON 更新表【英文标题】:Updating table based on JSON inside PostgreSQL function 【发布时间】:2021-12-15 23:47:49 【问题描述】:我正在编写一个 plpgsql 函数,它应该根据提供的 JSON 对象更新表。 JSON 包含一个表表示形式,其中包含与表本身相同的所有列。
函数目前看起来如下:
CREATE OR REPLACE FUNCTION update (updated json)
BEGIN
/* transfrom json to table */
WITH updated_vals AS (
SELECT
*
FROM
json_populate_recordset(NULL::my_table, updated)
),
/* Retrieve all columns from mytable and also with reference to updated_vals table */
cols AS (
SELECT
string_agg(quote_ident(columns), ',') AS table_cols,
string_agg('updated_vals.' || quote_ident($1), ',') AS updated_cols
FROM
information_schema
WHERE
table_name = 'my_table' -- table name, case sensitive
AND table_schema = 'public' -- schema name, case sensitive
AND column_name <> 'id' -- all columns except id and user_id
AND column_name <> 'user_id'
),
/* Define the table columns separately */
table_cols AS (
SELECT
table_cols
FROM
cols
),
/* Define the updated columns separately */
updated_cols AS (
SELECT
updated_cols
FROM
cols)
/* Execute the update statement */
EXECUTE 'UPDATE my_table'
|| ' SET (' || table_cols::text || ') = (' || updated_cols::text || ') '
|| ' FROM updated_vals '
|| ' WHERE my_table.id = updated_vals.id '
|| ' AND my_table.user_id = updated_vals.user_id';
COMMIT;
END;
我注意到WITH
子句与EXECUTE
的组合总是会触发错误syntax error at or near EXECUTE
,即使它们非常简单明了。是否确实如此,如果是这样,将所需变量(updated_vals
、table_cols
和updated_cols
)提供给EXECUTE
的替代方法是什么?
如果您对此代码有任何其他改进,我很高兴看到这些改进,因为我对 sql/plpgsql 非常陌生。
【问题讨论】:
【参考方案1】:如果您在函数中写入表名 (my_table
),这意味着您将始终只更新 JSON 数据中的一个指定表。因此,您可以手动在函数中写入表名和列名,而不是使用information_schema
。这是简单易行的方法。
例如:
CREATE OR REPLACE FUNCTION rbac.update_users_json(updated json)
RETURNS boolean
LANGUAGE plpgsql
AS $function$
begin
update rbac.users usr
set
username = jsn.username,
first_name = jsn.first_name,
last_name = jsn.last_name
from (
select * from json_populate_recordset(NULL::rbac.users, updated)
) jsn
where jsn.id = usr.id;
return true;
END;
$function$
;
【讨论】:
您确实正确地注意到我写了my_table
。然而,我提供的代码是真实代码的程式化示例。 my_table
将替换为动态表。【参考方案2】:
对于动态表:
CREATE OR REPLACE FUNCTION rbac.update_users_json_dynamic(updated json)
RETURNS boolean
LANGUAGE plpgsql
AS $function$
declare
f record;
exec_sql text;
sep text;
begin
exec_sql = 'update rbac.users usr set ' || E'\n';
sep = '';
for f in
select clm.column_name
from
information_schema."tables" tbl
inner join
information_schema."columns" clm on
clm.table_name = tbl.table_name
and clm.table_schema = tbl.table_schema
where
tbl.table_schema = 'test'
and tbl.table_name = 'users'
and clm.column_name <> 'id'
loop
exec_sql = exec_sql || sep || f.column_name || ' = ' || 'jsn.' || f.column_name;
sep = ', ' || E'\n';
end loop;
exec_sql = exec_sql || E'\n' || 'from (select * from json_populate_recordset(NULL::rbac.users, ''' ||
updated::text || ''')) jsn ' || E'\n' || 'where jsn.id = usr.id';
execute exec_sql;
return true;
END;
$function$
;
【讨论】:
以上是关于在 PostgreSQL 函数中基于 JSON 更新表的主要内容,如果未能解决你的问题,请参考以下文章