I'm trying to create function, which adds a record with given variables as values. My code:
CREATE OR REPLACE FUNCTION ADD_FILM(id INTEGER, t VARCHAR, y INTEGER, p REAL) RETURNS VARCHAR AS $$
DECLARE
query VARCHAR;
BEGIN
query = 'insert into films (id_film, title, year_production, price) values ('||id||','||t||','||y||','||p||')';
EXECUTE query;
RETURN 'OK';
EXCEPTION
WHEN UNIQUE_VIOLATION THEN
RAISE NOTICE 'Incorrect ID, next available ID set';
RETURN 0;
END;
$$ LANGUAGE PLPGSQL;
SELECT ADD_FILM(1,'aaa','2020','10');
Following function execution ends with error. What's wrong with syntax?
ERROR: column "aaa" does not exist
I'd rather do like this:
CREATE OR REPLACE FUNCTION ADD_FILM(id INTEGER, t VARCHAR, y INTEGER, p REAL) RETURNS
VARCHAR AS $$
BEGIN
insert into films (id_film, title, year_production, price) values (id,t,y,p);
RETURN 'OK';
....
....
See this link: https://www.postgresqltutorial.com/postgresql-create-procedure/
And call it:
CALL ADD_FILM(1,'aaa','2020','10');
Another possible solution with EXECUTE:
create table films
(
id_film int,
title varchar,
year_production int,
price real
);
CREATE TABLE
CREATE OR REPLACE FUNCTION ADD_FILM(id INTEGER, t VARCHAR, y INTEGER, p REAL) RETURNS VARCHAR AS $$
DECLARE
query VARCHAR;
BEGIN
query = 'insert into films (id_film, title, year_production, price) values ($1,$2,$3,$4)';
EXECUTE query USING id, t, y, p;
RETURN 'OK';
EXCEPTION
WHEN UNIQUE_VIOLATION THEN
RAISE NOTICE 'Incorrect ID, next available ID set';
RETURN 0;
END;
$$ LANGUAGE PLPGSQL;
CREATE FUNCTION
SELECT ADD_FILM(1,'aaa','2020','10');
add_film
----------
OK
(1 row)
select * from films;
id_film | title | year_production | price
---------+-------+-----------------+-------
1 | aaa | 2020 | 10
(1 row)
Related
I have two tables, e.g.:
CREATE TABLE table_1
(
one_column INTEGER,
two_column INTEGER,
three_column INTEGER
);
CREATE TABLE table_2
(
id SERIAL,
column_1 INTEGER,
column_2 INTEGER,
column_3 INTEGER,
name TEXT,
step INTEGER
);
I have a stored function which receives a number of parameters. Within the function, I need to INSERT a row into a table using a (dynamic?) combination of the results from a SELECT and two of the function parameters. Currently I've got something similar to the following pseudo-code...
CREATE OR REPLACE FUNCTION function_p (
p_id INTEGER,
p_name TEXT DEFAULT '',
p_step INTEGER DEFAULT NULL
)
RETURNS VOID AS $$
BEGIN
INSERT INTO table_2 (
column_1,
column_2,
column_3,
p_name,
p_step
)
SELECT
one_column,
two_column,
three_column
FROM table_1
WHERE id = p_id;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
Should the INSERT be more like this?
INSERT INTO table_2 (
column_1,
column_2,
column_3,
name,
step
)
(SELECT
one_column,
two_column,
three_column
FROM table_1
WHERE id = p_id),
p_name,
p_step;
Use format to create the insert statement. Also, you problably want a procedure, e.g.
CREATE OR REPLACE PROCEDURE function_p (
p_name TEXT DEFAULT '',
p_step INT DEFAULT NULL
)
LANGUAGE plpgsql AS $$
BEGIN
EXECUTE format('
INSERT INTO table_2 (column_1,column_2,column_3,name,step)
SELECT one_column, two_column,three_column,%L,%s
FROM table_1',p_name,p_step);
END;
$$
Keep in mind that the columns number (and types) used in the INSERT statement has to match with those coming from the SELECT.
Demo: db<>fiddle
Sample Problem with queries Link
Not able to get any inserted row in the RETURNING statement with INSERT and SELECT command even after adding RETURN NEXT; RETURN ;
SCHEMA FOR USER TABLE
create table "user" (name text not null, updated_time TIMESTAMP NOT
NULL DEFAULT CURRENT_TIMESTAMP );
function which needs to be updated to return inserted rows
CREATE OR REPLACE FUNCTION testFn()
RETURNS table (name character varying , updated_time timestamp without time zone ) AS $$ DECLARE BEGIN
insert into "user" (name , updated_time)
select 'alex',now()
union
select 'alex2',now()
returning name, updated_time;
END;
$$ LANGUAGE plpgsql;
This function only inserts into DB but doesnt return the inserted rows with updated time on calling the function
it return no output on
select * from testFn()
Make it a language sql function:
CREATE OR REPLACE FUNCTION testFn()
RETURNS table (name character varying , updated_time timestamp without time zone )
AS
$$
insert into "user" (name , updated_time)
values
('alex', now()),
('alex2', now())
returning "user".name, "user".updated_time;
$$
LANGUAGE sql;
With a language plpgsql you would need a return query, rather then just putting the insert into it.
CREATE OR REPLACE FUNCTION testFn()
RETURNS table (name character varying , updated_time timestamp without time zone )
AS
$$
begin
return query
insert into "user" (name , updated_time)
values
('alex', now()),
('alex2', now())
returning "user".name, "user".updated_time;
end;
$$
LANGUAGE plpgsql;
To run the function use:
select *
from testfn();
Online example
It is much simpler to do with a language sql function. Try this (based on the previous version of your function):
CREATE OR REPLACE FUNCTION sp_post_items(i_data json)
RETURNS table (fulfiller_id text,item_id text, order_id text, status_id integer, item_updated_time timestamp)
AS $function$
insert into vw_item_status_detail
(fulfiller_id ,item_id ,order_id , status_id, sku_code, decoration_technology, quantity, item_updated_time)
select
i_data->>'fulfillerId',
t->>'itemId',
i_data->>'orderId',
1000,
t->>'skuCode',
t->>'decorationTechnology',
10,
now()
from json_array_elements(i_data -> 'items') t
returning fulfiller_id, item_id, order_id, status_id, item_updated_time;
$function$
LANGUAGE sql;
or for the updated function:
CREATE OR REPLACE FUNCTION testFn()
RETURNS table (name text, updated_time timestamp without time zone ) AS
$$
insert into "user" (name , updated_time)
select 'alex',now()
union
select 'alex2',now()
returning name, updated_time;
$$ LANGUAGE sql;
In PostgreSQL database I have table which looks like this:
| question_id | question_text | widget | required | position |
|-------------|---------------|--------|----------|----------|
| int | text | int | boolean | int |
Second table which called factors_questions_relationship looks like this:
| factor_id | question_id |
|-------------|---------------|
| int | text |
I am trying to create function which would create multiple rows and return array of ids of new created entries. How correctly to make such function?
CREATE OR REPLACE FUNCTION factorio(
FACTOR_IDENTIFIER INT,
TEXT_ARR VARCHAR[],
WIDGET_ARR INT[],
REQUIRED_ARR BOOLEAN[],
POSITION_ARR INT[]
) RETURNS SETOF INT AS $$
BEGIN
RETURN QUERY
WITH RESULT_SET AS (
INSERT INTO QUESTIONS (TEXT, WIDGET, REQUIRED, POSITION)
SELECT
UNNEST(ARRAY[TEXT_ARR]) AS TEXT,
UNNEST(ARRAY[WIDGET_ARR]) AS WIDGET,
UNNEST(ARRAY[REQUIRED_ARR]) AS REQUIRED,
UNNEST(ARRAY[POSITION_ARR]) AS POSITION
RETURNING ID
)
--
INSERT INTO factors_questions_relationship (FACTOR_ID, QUESTION_ID)
SELECT FACTOR_IDENTIFIER FACTOR_ID, QUESTION_ID FROM UNNEST(ARRAY[array_agg(SELECT ID FROM RESULT_SET)]) QUESTION_ID
--
SELECT ID FROM RESULT_SET;
END;
$$ LANGUAGE plpgsql;
You can simply unnest them in columns
select
unnest(array['quick','brown','fox']) as question_text,
unnest(array[1,2,3]) as widget_id
Whereas putting them in FROM clause, would result to cartesian product:
select question_text, widget_id
from
unnest(array['quick','brown','fox']) as question_text,
unnest(array[1,2,3]) as widget_id
Output:
To obtain the Ids generated from newly-inserted records, use return query + returning id combo. Sample test:
create table z
(
id int generated by default as identity primary key,
question_text text
);
create or replace function insert_multiple_test()
returns table (someid int) as
$$
begin
return query
with resulting_rows as
(
insert into z(question_text) values
('hello'),
('你好'),
('hola')
returning id
)
select id from resulting_rows;
end;
$$ language 'plpgsql';
select * from insert_multiple_test();
Output:
Here's for SETOF:
create table z(id int generated by default as identity primary key, question_text text);
create or replace function insert_multiple_test()
returns setof int
as
$$
begin
return query
with resulting_rows as
(
insert into z(question_text) values
('hello'),
('你好'),
('hola')
returning id
)
select id from resulting_rows;
end;
$$ language 'plpgsql';
select x.the_id from insert_multiple_test() as x(the_id);
Output:
If you don't need to run multiple queries, you can just use LANGUAGE 'sql', it's simpler:
create table z
(
id int generated by default as identity primary key,
question_text text
);
create or replace function insert_multiple_test()
returns setof int as
$$
insert into z(question_text) values
('hello'),
('你好'),
('hola')
returning id;
$$ language 'sql';
select x.id_here from insert_multiple_test() as x(id_here);
Output:
I have a postgresql table with sequence:
CREATE TABLE A (
id integer NOT NULL DEFAULT nextval('a_seq'::regclass),
X integer,
Y integer,
Z boolean default false,
CONSTRAINT A_pkey PRIMARY KEY (id)
)
I have an insert statment in function as follows:
insert into A(x,y) select $1,getdig();
i want this insert to return the id the row was given to a function varabile called A_id
It should be something like:
CREATE OR REPLACE FUNCTION bbb(m integer)
RETURNS integer AS
$BODY$
declare
A_id int;
begin
insert into A(x,y) select $1,getdig() RETURNING id into A_id;
actions using A_id like:
update A set z=True where id=A_id;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
How do I do that?
There is no need for the select:
CREATE OR REPLACE FUNCTION bbb(m integer)
RETURNS integer AS
$BODY$
declare
A_id int;
begin
insert into A(x,y)
values ($1,getdig())
RETURNING id into A_id;
-- actions using A_id like:
update A set z=True where id=A_id;
return a_id; -- don't forget to return something!
end;
$BODY$
LANGUAGE plpgsql VOLATILE
You use the returning clause:
with i as (
insert into A(x,y)
select $1, getdig()
returning id
)
select *
from i;
Technically, the CTE is not necessary. But I prefer that queries that return values start with SELECT.
i have created a function in PostgreSQL to insert to the following
CREATE TABLE gtab83
(
orderid integer NOT NULL DEFAULT nextval('seq_gtab83_id'::regclass),
acid integer,
slno integer,
orderdte date
)
and created Function is
CREATE OR REPLACE FUNCTION funcInsert(iacid int,islno int,idate date) RETURNS int AS
$$
declare id_val int;
BEGIN
INSERT INTO GTAB83 (acid,slno,orderdte) VALUES (iacid,islno,idate) RETURNING orderid
into id_val;
return id_val;
END;
$$
LANGUAGE plpgsql;
when a execute the above function
select funcInsert(666,13,'2014-06-06'
getting this error
ERROR: query has no destination for result data
CONTEXT: PL/pgSQL function procgtab83(integer,integer,date) line 3 at SQL statement
create or replace function funcinsert(iacid int, islno int, idate date)
returns int as $$
declare id_val int;
begin
with i as (
insert into gtab83 (acid,slno,orderdte)
values (iacid,islno,idate)
returning orderid
)
select orderid into id_val
from i;
return id_val;
end;
$$ language plpgsql;
It can be much simpler as plain sql
create or replace function funcinsert(iacid int, islno int, idate date)
returns int as $$
insert into gtab83 (acid,slno,orderdte)
values (iacid,islno,idate)
returning orderid
;
$$ language sql;
This code is working:
postgres=# create table xx(a int);
CREATE TABLE
postgres=# create or replace function bu(int) returns int as
$$declare x int;
begin
insert into xx values($1) returning a into x;
return x;
end $$ language plpgsql;
CREATE FUNCTION
postgres=# select bu(10);
bu
────
10
(1 row)
And because it is same code as your, I expect, so you use some very old Postgres. I remember similar bug in pg, but it is more than five years fixed.