Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Insert data in 3 tables at a time using Postgres

I want to insert data into 3 tables with a single query.
My tables looks like below:

CREATE TABLE sample (    id        bigserial PRIMARY KEY,    lastname  varchar(20),    firstname varchar(20) );  CREATE TABLE sample1(    user_id    bigserial PRIMARY KEY,    sample_id  bigint REFERENCES sample,    adddetails varchar(20) );  CREATE TABLE sample2(    id      bigserial PRIMARY KEY,    user_id bigint REFERENCES sample1,    value   varchar(10) ); 

I will get a key in return for every insertion and I need to insert that key in the next table.
My query is:

insert into sample(firstname,lastname) values('fai55','shaggk') RETURNING id; insert into sample1(sample_id, adddetails) values($id,'ss') RETURNING user_id; insert into sample2(user_id, value) values($id,'ss') RETURNING id; 

But if I run single queries they just return values to me and I cannot reuse them in the next query immediately.

How to achieve this?

like image 812
Faisal Avatar asked Dec 13 '13 07:12

Faisal


People also ask

How do I run multiple INSERTs in PostgreSQL?

PostgreSQL INSERT Multiple Rows First, specify the name of the table that you want to insert data after the INSERT INTO keywords. Second, list the required columns or all columns of the table in parentheses that follow the table name. Third, supply a comma-separated list of rows after the VALUES keyword.

Can we join 3 tables in PostgreSQL?

2) Using PostgreSQL INNER JOIN to join three tables And each payment is processed by one and only one staff.

How do I insert two tables at the same time?

The T-SQL function OUTPUT, which was introduced in 2005, can be used to insert multiple values into multiple tables in a single statement. The output values of each row that was part of an INSERT, UPDATE or DELETE operation are returned by the OUTPUT clause.

How do I insert data from multiple tables into one table?

Example 5: INSERT INTO SELECT statement with Join clause to get data from multiple tables. We can use a JOIN clause to get data from multiple tables. These tables are joined with conditions specified with the ON clause. Suppose we want to get data from multiple tables and insert into a table.


1 Answers

Use data-modifying CTEs:

WITH ins1 AS (    INSERT INTO sample(firstname, lastname)    VALUES ('fai55', 'shaggk') -- ON     CONFLICT DO NOTHING         -- optional addition in Postgres 9.5+    RETURNING id AS sample_id    ) , ins2 AS (    INSERT INTO sample1 (sample_id, adddetails)    SELECT sample_id, 'ss' FROM ins1    RETURNING user_id    ) INSERT INTO sample2 (user_id, value) SELECT user_id, 'ss2' FROM ins2; 

Each INSERT depends on the one before. SELECT instead of VALUES makes sure nothing is inserted in subsidiary tables if no row is returned from a previous INSERT. (Since Postgres 9.5+ you might add an ON CONFLICT.)
It's also a bit shorter and faster this way.

Typically, it's more convenient to provide complete data rows in one place:

WITH data(firstname, lastname, adddetails, value) AS (    VALUES                              -- provide data here       ('fai55', 'shaggk', 'ss', 'ss2') -- see below     , ('fai56', 'XXaggk', 'xx', 'xx2') -- works for multiple input rows        --  more?                          ) , ins1 AS (    INSERT INTO sample (firstname, lastname)    SELECT firstname, lastname          -- DISTINCT? see below    FROM   data    -- ON     CONFLICT DO NOTHING       -- UNIQUE constraint? see below    RETURNING firstname, lastname, id AS sample_id    ) , ins2 AS (    INSERT INTO sample1 (sample_id, adddetails)    SELECT ins1.sample_id, d.adddetails    FROM   data d    JOIN   ins1 USING (firstname, lastname)    RETURNING sample_id, user_id    ) INSERT INTO sample2 (user_id, value) SELECT ins2.user_id, d.value FROM   data d JOIN   ins1 USING (firstname, lastname) JOIN   ins2 USING (sample_id); 

db<>fiddle here

You may need explicit type casts in a stand-alone VALUES expression - as opposed to a VALUES expression attached to an INSERT where data types are derived from the target table. See:

  • Casting NULL type when updating multiple rows

If multiple rows can come with identical (firstname, lastname), you may need to fold duplicates for the first INSERT:

... INSERT INTO sample (firstname, lastname) SELECT DISTINCT firstname, lastname FROM data ... 

You could use a (temporary) table as data source instead of the CTE data.

It would probably make sense to combine this with a UNIQUE constraint on (firstname, lastname) in the table and an ON CONFLICT clause in the query.

Related:

  • How to use RETURNING with ON CONFLICT in PostgreSQL?
  • Is SELECT or INSERT in a function prone to race conditions?
like image 187
Erwin Brandstetter Avatar answered Nov 10 '22 04:11

Erwin Brandstetter