【问题标题】:PostgreSQL 9.3 - How to insert using json_populate_recordset but still get auto ids by sequencePostgreSQL 9.3 - 如何使用 json_populate_recordset 插入但仍按顺序获取自动 ID
【发布时间】:2014-11-25 12:52:27
【问题描述】:

这是“Populate multiple tables from a single JSON object with json_populate_recordset”的后续问题。

假设我的表 (table_a, table_b) 有 a_id 和 b_id 的序列, 所以它们看起来像这样:

CREATE TABLE table_a (a_id serial, b_id integer, c_id integer);
CREATE TABLE table_b (b_id serial, name text, z_id integer);
...
CREATE TABLE table_z (z_id serial, some_text_entry text);

一个像这样的常规插入

INSERT INTO table_a (b_id, c_id) values (1, 2);
INSERT INTO table_b (name, z_id) values ("whatever", 3);
...
INSERT INTO table_z (some_text_entry) values ("Some text");

让 PostgreSQL 增加 a_id (table_a)、b_id(table_b) 等的 id,以便可以创建和存储新数据集。

但是我怎样才能使用以下更复杂的方法插入数据并仍然获得自动创建的 ID?

WITH input AS (
   SELECT '{
      "tablename_a":[{"a_id":1,"b_id":2,"c_id":3},
       {"a_id":2,"b_id":51,"c_id":3}],
      "tablename_b":[{"b_id":2,"name":"John Doe", "z_id":123},
       {"b_id":51,"name":"Mary Ann", "z_id":412}],
      "tablename_z":[{"z_id":123, "some_text_entry":"Something"},
      {"z_id":123, "some_text_entry":"Something else"}]
      }'::json AS j
   )
,  a AS (
   INSERT INTO tablename_a
   SELECT t.*
   FROM   input i
        , json_populate_recordset(NULL::tablename_a, i.j->'tablename_a') t
   )
,  b AS (
   INSERT INTO table_b
   SELECT t.*
   FROM   input i
        , json_populate_recordset(NULL::tablename_b, i.j->'tablename_b') t
   )
   -- ... more ...
INSERT INTO tablename_z
SELECT t.*
FROM   input i
     , json_populate_recordset(NULL::tablename_z, i.j->'tablename_z') t
;

如果我只是将 id 设置为 null

"tablename_a":[{"a_id": null,"b_id":2,"c_id":3},
       {"a_id": null,"b_id":51,"c_id":3}]

或者像这样省略各自的ID:

"tablename_a":[{"b_id":2,"c_id":3},
       {"b_id":51,"c_id":3}]

我收到错误“a_id”列中的空值违反非空约束。

另外: 如果有办法解决这个问题,而不是专门列出所有列名(序列名除外),那就太好了。

如果你在 MySQL 中使用我的 table_a,我知道你可以做类似的事情

INSERT INTO table_a VALUES (1,2)

意味着 MySQL 将使用自动增量 id 填充 a_id 字段,其余部分使用插入命令给出的数据。用json也没有办法做到这一点吗?

【问题讨论】:

    标签: sql json postgresql


    【解决方案1】:

    通常,当您想要插入具有serialbigserial 类型列的表中时,您从列列表中省略该列。我试图尽可能少地改变你原来的语法来展示它是如何工作的。

    -- I made no changes to the CTE, except to cut some lines.
    WITH input AS (
       SELECT '{
          "tablename_a":[{"a_id":1,"b_id":2,"c_id":3}, {"a_id":2,"b_id":51,"c_id":3}]
          }'::json AS j
    )
    -- Ignore a_id. It's set automatically by PostgreSQL. 
    -- Think about cutting it from input.
    INSERT INTO table_a (b_id, c_id)
    SELECT b_id, c_id
    FROM   input i
         , json_populate_recordset(NULL::table_a, i.j->'tablename_a') t
    

    【讨论】:

    • 谢谢!有没有办法在不专门命名所有列的情况下做到这一点(但当然是 id-ones)?由于有很多表和列,如果有可能给 postgres json 并且它知道它必须自己填充 serial 字段,那就太好了。
    • “有没有办法做到这一点,而无需专门命名所有列...”我想不出一个简单的方法。跨度>
    • 在此期间我被分配到另一个项目,但现在我又遇到了这个问题。我尝试了您的解决方案,它运行没有错误(-> 12 行在 45 毫秒内受到影响),但它实际上并没有插入任何东西。由于大多数带有 INSERT 和命名列的示例也使用 VALUES,因此我尝试将其插入“SELECT b_id, c_id”之前。但这根本行不通。有什么想法吗?
    • 我复制并执行了您的CREATE TABLE table_a... 语句和我回答中的查询。运行没有错误,创建了两行。 PostgreSQL 在不插入 12 行的情况下报告 12 行受影响是没有意义的。仔细检查表格和您的查询。如果您使用的是 pgAdminIII,也请查看“历史记录”选项卡。
    • 我的错,对不起。我在我的编辑器中尝试了查询,它在执行后有一些自动反转(如未提交的事务)。所以,是的,它有效:-)
    猜你喜欢
    • 2019-05-01
    • 1970-01-01
    • 2012-01-18
    • 2013-02-28
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-26
    相关资源
    最近更新 更多