我正在尝试INSERT
一条记录,返回 ID,然后将 ID 传递给其他表并插入其他数据。插入的数据为JSON格式。
我正在使用函数调用来插入数据,虽然创建语句有效,但我在执行过程中做错了(所以 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"}]'
);
我的预期输出应该是 main_data
表填充了 1 行,locale_data
表填充了 2 行,demographic_data
表填充了有 2 行。
locale
和 demographic
表中的每一行都属于并且应该引用 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 的数据插入。
最佳答案
主要问题 - 使用 jsonb_populate_recordset()
时,您必须确保 json 值的数量与表列的数量完全相同。您不想填充表的 id
,因为它们是连续的,因此您必须指明列列表和适当的选择列表。此外,函数 jsonb_populate_recordset()
适用于 json 数组,因此第一个参数必须是一个数组,就像其他两个一样。
公共(public)表表达式(带命令)是一个包含多个子查询的查询,因此函数语言应该是 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"}]'
);
关于sql - 用于填充记录集和返回 ID 的 Postgres 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47103993/