2017-11-03 11 views
2

レコードをINSERTにしようとしていますが、IDを返してから別のテーブルにIDを渡し、追加データを挿入します。挿入するデータはJSON形式です。Postgresでレコードセットと返されたIDを取り込む機能

私はデータを挿入するために関数呼び出しを使用していますが、作成ステートメントが動作している間に、実行中に何か間違っています(そのために)か、文を正しく書かなかったかb)データを適切に渡す)。

私は取得していますエラーは、次のとおりです。ここで

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行目、2行、2列を移入demographic_dataテーブル移入locale_dataテーブル移入main_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文の私の第二セットはmiswrittenされていることを推測するが、私は別の操作からIDを返した後にJSONのデータ挿入を処理する方法が不明です。

+0

は 'レコードセットを返すjsonb_populate_recordset'。文字列でない –

+0

これはあなたのために働くかもしれませんhttps://stackoverflow.com/questions/27215216/postgres-how-to-convert-json-string-to-text postgres 9.4+ –

答えて

1

主な問題 - jsonb_populate_recordset()を使用する場合は、json値の数と表の列の数が完全に同じであることを確認する必要があります。テーブルのidをシリアルとして入力したくないので、列リストと適切な選択リストを指定する必要があります。さらに、関数jsonb_populate_recordset()はjson配列に作用するので、最初の引数は2つの配列のように配列でなければなりません。

(コマンドを使用して)共通表expresionは、いくつかのサブクエリを持つ単一のクエリであるため、機能言語は、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.

関連する問題