【问题标题】:Updating table based on JSON inside PostgreSQL function在 PostgreSQL 函数中基于 JSON 更新表
【发布时间】: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_valstable_colsupdated_cols)提供给EXECUTE 的替代方法是什么?

如果您对此代码有任何其他改进,我很高兴看到这些改进,因为我对 sql/plpgsql 非常陌生。

【问题讨论】:

    标签: sql postgresql function


    【解决方案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$
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多