繁体   English   中英

将 json 嵌套提取到 postgres 表中

[英]Nested json extraction into postgres table

我使用以下查询来解析 json 元素并将其存储到表“pl”中,“test”表用于存储原始 json。

select     
           each_attribute ->> 'id' id,
           each_attribute ->> 'sd' sd,
           each_attribute ->> 'v' v
from       test
cross join json_array_elements(json_array) each_section
cross join json_array_elements(each_section -> 'firstt') each_attribute

我可以使用上述查询查看以下 json 值,但无法使用 json_populate_recordset 将其插入到另一个表中。

表定义我需要将嵌套的 json 插入:id 整数、字符变化(6666)、字符变化(99999)

Table1(对于上述定义)应该存储键 firstt 的值 Table2(对于上述定义)应该存储键 secondt 的值

json格式:

{
 "firstt": [
    {
      "id": 1,
      "sd": "test3",
      "v": "2223"
    },
    {
      "id": 2,
      "sd": "test2",
      "v": "2222"
    }],
"secondt": [
    {
      "id": 1,
      "sd": "test3",
      "v": "2223"
    },
    {
      "id": 2,
      "sd": "test2",
      "v": "2222"
    }]
}

请协助。 我已经尝试了 stackoverflow 解决方案中的所有可能的事情,但没有为像这样的嵌套数组提供任何用于插入的内容。

为动态查询添加代码。 这没用。 错误 -“格式参数太少”。

do $$
DECLARE
my record;
tb_n varchar(50);
BEGIN
FOR my IN 
  SELECT json_object_keys(json_array) as t FROM test
LOOP
tb_n := my.t;

EXECUTE format($$ WITH tbl_record_arrays as(
     SELECT
     entries.*
     FROM
       test
     JOIN LATERAL json_each(json_array) as entries(tbl_name,tbl_data_arr) ON TRUE
)
INSERT INTO %I
    SELECT
     records.*
     FROM
        tbl_record_arrays
          JOIN LATERAL json_populate_recordset(null::%I,tbl_data_arr) records ON TRUE
     WHERE
      tbl_name = %I$$,tb_n);
END LOOP;
END;
$$;

要创建一个将指定键的 json 数组动态插入指定表的 plpgsql 函数,您可以执行以下操作:

CREATE OR REPLACE FUNCTION dynamic_json_insert(key_name text,tbl text) RETURNS VOID AS $$
    BEGIN
    -- the $<tag>$ syntax allows for generating a multiline string
    EXECUTE format($sql$
    INSERT INTO %1$I
        SELECT
          entries.*
        FROM test
        JOIN LATERAL json_populate_recordset(null::%1$I,json_data -> $1) as entries ON TRUE;
    $sql$::text,tbl) USING dynamic_json_insert.key_name;
     END;

$$ LANGUAGE plpgsql
   VOLATILE --modifies data
   STRICT -- Returns NULL if any arguments are NULL
   SECURITY INVOKER; --Execute this function with the Role of the caller, rather than the Role that defined the function;

并称它为

SELECT dynamic_json_insert('firstt','table_1')

如果要使用多个键值对插入到多个表中,可以创建一个 plpgsql 函数,该函数采用键、表对的variadic数组,然后在单个原子语句中生成具有所有 INSERT 的单个通用表表达式 (CTE) .

首先创建一个自定义类型:

CREATE TYPE table_key as (
    tbl_key text,
    relation regclass -- special type that refers to a Postgresql relation
);

然后定义函数:

CREATE OR REPLACE FUNCTION dynamic_json_insert(variadic table_keys table_key[]) RETURNS VOID AS $$
    DECLARE
      tbl_key_len integer = array_length(dynamic_json_insert.table_keys,1);
    BEGIN
        IF tbl_key_len > 0 THEN
        EXECUTE (
        --generates a single atomic insert CTE when there are multiple table_keys OR a single insert statement otherwise
        --the SELECT is enclosed in parenthesis because it generates a single text value which EXECUTE receives.
        SELECT
    
         --append WITH if We have more than 1 table_key (for CTE)
         CASE WHEN tbl_key_len > 1 THEN 'WITH ' ELSE '' END
         || string_agg(
          CASE
             WHEN
              --name the auxiliary statement and put it in parenthesis.
              is_aux THEN  format('%1$I as (%2$s)','ins_' || tk.tbl_key,stmt) || end_char
            ELSE stmt
          END,E'\n') || ';'
        FROM
          --unnest the table_keys argument and get its index (rn)
          unnest(dynamic_json_insert.table_keys) WITH ORDINALITY AS tk(tbl_key,relation,rn)
          -- the JOIN LATERAL here means "for each unnested table_key, generate the rows of the following subquery"
          JOIN LATERAL (
           SELECT
             rn < tbl_key_len is_aux,
             --we need a comma between auxiliary statements
             CASE WHEN rn = tbl_key_len - 1 THEN '' ELSE ',' END end_char,
            --dynamically generate INSERT statement
             format($sql$
             INSERT INTO %1$I
                SELECT
                  entries.*
                FROM test
                JOIN LATERAL json_populate_recordset(null::%1$I,json_data -> %2$L) as entries ON TRUE
             $sql$::text,tk.relation,tk.tbl_key) stmt
            ) stmts ON TRUE
        );
        END IF;
    END;
$$ LANGUAGE plpgsql
    VOLATILE --modifies data
    STRICT -- Returns NULL if any arguments are NULL
    SECURITY INVOKER; --Execute this function with the Role of the caller, rather than the Role that defined the function;

然后像这样调用函数:

SELECT dynamic_json_insert(
  ('firstt','table_1'),
  ('secondt','table_2')
);

由于使用了variadic关键字,您可以将数组的每个元素作为单独的参数传入,Postgres 将自动转换为适当的类型。

上述函数调用生成/执行的 SQL 将是:

WITH ins_firstt as (
             INSERT INTO table_1
                SELECT
                  entries.*
                FROM test
                JOIN LATERAL json_populate_recordset(null::table_1,json_data -> 'firstt') as entries ON TRUE
             )

             INSERT INTO table_2
                SELECT
                  entries.*
                FROM test
                JOIN LATERAL json_populate_recordset(null::table_2,json_data -> 'secondt') as entries ON TRUE
             ;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM