Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Postgres Function to insert multiple records in two tables

create table public.orders (
    orderID serial PRIMARY KEY,
    orderdate timestamp NOT NULL
);

create table public.orderdetails (
    orderdetailID serial PRIMARY KEY,
    orderID integer REFERENCES public.orders(orderID),
    item varchar(20) NOT NULL,
    quantity INTEGER NOT NULL
);

I have (very simplified sample) tables as above, into which I want to insert details of an order and order details in one action.

I am familiar with transactions, and could insert data with an SQL command like the below:

DO $$
  DECLARE inserted_id integer;
  BEGIN
    INSERT INTO public.orders(orderdate) VALUES (NOW()) RETURNING orderID INTO inserted_id;

    INSERT INTO public.orderdetails(orderID, item, quantity)
    VALUES (inserted_id, 'Red Widget', 10),
           (inserted_id, 'Blue Widget', 5);
  END
$$ LANGUAGE plpgsql;

However, ideally I'd like to have a query like the above a function if possible, rather than being stored within my application.

Could anyone point me in the right direction for supplying multiple records to a postgres function? Alternatively, if what I am looking to do is considered bad practice, please let me know what other route I should follow.

Thanks in advance.

like image 643
Devasta Avatar asked Sep 20 '16 22:09

Devasta


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 insert data into two tables simultaneously?

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 multiple records in a table?

INSERT-SELECT-UNION query to insert multiple records Thus, we can use INSERT-SELECT-UNION query to insert data into multiple rows of the table. The SQL UNION query helps to select all the data that has been enclosed by the SELECT query through the INSERT statement.

What is Upsert in PostgreSQL?

The UPSERT statement is a DBMS feature that allows a DML statement's author to either insert a row or if the row already exists, UPDATE that existing row instead. That is why the action is known as UPSERT (simply a mix of Update and Insert).


2 Answers

You can use an array of tuples to pass multiple rows to the function. You need a custom type:

create type order_input as (
    item text,
    quantity integer);

Use array of this type for an argument of the function:

create or replace function insert_into_orders(order_input[])
returns void language plpgsql as $$
declare 
    inserted_id integer;
begin
    insert into public.orders(orderdate) 
    values (now()) 
    returning orderid into inserted_id;

    insert into public.orderdetails(orderid, item, quantity)
    select inserted_id, item, quantity
    from unnest($1);
end $$;

Usage:

select insert_into_orders(
    array[
        ('Red Widget', 10), 
        ('Blue Widget', 5)
    ]::order_input[]
);

select * from orderdetails;

 orderdetailid | orderid |    item     | quantity 
---------------+---------+-------------+----------
             1 |       1 | Red Widget  |       10
             2 |       1 | Blue Widget |        5
(2 rows)
like image 128
klin Avatar answered Oct 01 '22 23:10

klin


Thanks Klin. That helped a lot.

Further, I was able to avoid the usage of an explicit type and just having used the table defined as an array.

Code below:

-- Create table whose type will be passed as input parameter
create table tbl_card
(id integer,
name varchar(10),
cardno bigint)

-- Create function to accept an array of table
create or replace function fn_insert_card_arr (tbl_card[]) returns integer as $$
begin
insert into tbl_card (id, name,cardno)
select id, name, cardno
from unnest($1);

return 0;
end;
$$ LANGUAGE plpgsql;

-- Execute function by passing an array of table (type casted to array of type table)
select fn_insert_card_arr(
array[
    (1,'one', 2222777744448888), 
    (2,'two', 8888444466662222),
    (3,'three', 2222777744448888), 
    (4,'four', 8888444466662222)
]::tbl_card[]
);
like image 40
Syamjith Avatar answered Oct 02 '22 01:10

Syamjith