【问题标题】:Postgres Function to Populate Recordset and Returned ID用于填充记录集和返回 ID 的 Postgres 函数
【发布时间】:2018-04-16 16:06:12
【问题描述】:

我正在尝试 INSERT 一条记录,返回 ID,然后将 ID 传递给其他表并插入附加数据。插入的数据为JSON格式。

我正在使用函数调用来插入数据,虽然 create 语句有效,但在执行过程中我做错了(所以要么a)我没有正确编写语句,要么 b)我没有t 正确传递数据)。

我得到的错误是这样的:

ERROR: INSERT has more target columns than expressions
SQL state: 42601
Context: PL/pgSQL function insert_to_tables(jsonb,jsonb,jsonb) line 3 at SQL statement

这是我的表格的外观:

CREATE TABLE main_data(
  id SERIAL PRIMARY KEY,
  field_1 TEXT,
  some_time DATE
);

CREATE TABLE locale_data(
  locale_id SERIAL PRIMARY KEY,
  city TEXT,
  state TEXT,
  address TEXT,
  main_data_id INTEGER REFERENCES main_data(id)
);

CREATE TABLE demographic_data(
  demographic_id SERIAL PRIMARY KEY,
  age INT,
  ethnicity TEXT,
  main_data_id INTEGER REFERENCES main_data(id)
);

我有一个这样的函数来处理数据输入和解析:

CREATE OR REPLACE FUNCTION insert_to_tables (
main_data_fields JSONB,
locale_data_fields JSONB,
demographic_data_fields JSONB,
OUT new_user_id INTEGER
)
RETURNS integer AS $$
BEGIN
   WITH ins AS (
      INSERT INTO main_data SELECT * FROM jsonb_populate_recordset(NULL::main_data, $1::jsonb)
      RETURNING id
      )

   INSERT INTO locale_data(city, state, address, main_data_id)
   SELECT i.id AS main_data_id, jsonb_populate_recordset(NULL::locale_data, $2::jsonb)
   FROM  ins i;
   INSERT INTO demographic_data(age, ethnicity)
   SELECT i.id AS main_data_id, jsonb_populate_recordset(NULL::demographic_data, $3::jsonb)
   FROM  ins i;
END;
$$ LANGUAGE plpgsql;

为了插入数据,我这样调用函数:

select insert_to_tables(
'{"field_1": "http://www.google.com", "some_time": "09-02-2019"}',
'[{"city": "a city", "address": "123 fake road", "state": "CA"}, {"city": "little city", "address": "456 noname road", "state": "WA"}]',
'[{"age": 45, "ethnicity": "Asian"}, {"age": "45", "ethnicity": "Egyptian"}]'
);

我的预期输出应该是填充了 1 行的 main_data 表、填充了 2 行的 locale_data 表和填充了 2 行的 demographic_data 表。

localedemographic 表中的每一行都属于并应该引用main_data 表中的行,如下所示:

id  |         field1_1        | some_time  |
----+-------------------------+------------+
 1  |  http://www.google.com  |  09-02-2019


locale_id  |    city        |  state  |     address      | main_data_id
-----------+----------------+---------+------------------+---------+
 1         |     a city     |   CA    | 123 fake road    |   1
 2         |   little city  |   WA    | 456 noname road  |   1

locale_id  |    age      |    ethnicity   |  main_data_id
-----------+-------------+----------------+------------------+
 1         |     45      |   Asian        |    1
 2         |     45      |   Egyptian     |    1 

我猜我的第二组INSERT INTO 语句写错了,但我不确定在从另一个操作返回ID 后如何处理JSON 的数据插入。

【问题讨论】:

标签: sql database postgresql insert plpgsql


【解决方案1】:

主要问题——当使用jsonb_populate_recordset()时,你必须确保json值的数量与表格列的数量完全相同。您不想填充表的id,因为它们是串行的,因此您必须指明列列表和适当的选择列表。此外,jsonb_populate_recordset() 函数适用于 json 数组,因此第一个参数必须是一个数组,就像其他两个一样。

普通表表达式(带命令)是单个查询有多个子查询,所以函数语言应该是SQL,最终查询应该返回插入main_data的行的id

CREATE OR REPLACE FUNCTION insert_to_tables (
    main_data_fields JSONB,
    locale_data_fields JSONB,
    demographic_data_fields JSONB
)
RETURNS integer AS $$
    WITH ins AS (
        INSERT INTO main_data (field_1, some_time)
        SELECT field_1, some_time
        FROM jsonb_populate_recordset(NULL::main_data, $1::jsonb)
        RETURNING id
    ),
    ins_locale AS (
        INSERT INTO locale_data (city, state, address, main_data_id)
        SELECT city, state, address, ins.id
        FROM ins, jsonb_populate_recordset(NULL::locale_data, $2::jsonb)
    ),
    ins_demographic AS (
        INSERT INTO demographic_data (age, ethnicity, main_data_id)
        SELECT age, ethnicity, ins.id
        FROM ins, jsonb_populate_recordset(NULL::demographic_data, $3::jsonb)
    )
    SELECT id
    FROM ins;
$$ LANGUAGE sql;

SELECT insert_to_tables (
    '[{"field_1": "http://www.google.com", "some_time": "09-02-2019"}]',
    '[{"city": "a city", "address": "123 fake road", "state": "CA"}, {"city": "little city", "address": "456 noname road", "state": "WA"}]',
    '[{"age": 45, "ethnicity": "Asian"}, {"age": "45", "ethnicity": "Egyptian"}]'
);

See the full example here.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-23
    • 1970-01-01
    • 2020-10-11
    • 1970-01-01
    • 2014-07-16
    • 1970-01-01
    • 2011-01-25
    相关资源
    最近更新 更多