PL/pgSQL - insert multiple rows, returning the ids in a resultset - postgresql

I am using PostgreSQL 8.4. My goal is to insert multiple rows with the help of PL/pgSQL and return the id-s of the inserted records back in a recordset.
At first I tried to do it in a single row, using the following code for my permission_create(..) function:
CREATE FUNCTION permission_create(
IN method permission.permission_method % TYPE,
IN resource permission.permission_resource % TYPE
)
RETURNS TABLE(id permission.permission_id % TYPE)
AS
$BODY$
BEGIN
RETURN QUERY
WITH inserted_permission AS (
INSERT INTO permission (permission_id, permission_method, permission_resource) VALUES (DEFAULT, method, resource)
RETURNING permission_id
)
SELECT
inserted_permission.permission_id AS id
FROM inserted_permission;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
However, I got the following error message:
[2013-07-04 17:38:01] [00000] type reference permission.permission_method%TYPE converted to character varying
[2013-07-04 17:38:01] [00000] type reference permission.permission_resource%TYPE converted to character varying
[2013-07-04 17:38:01] [00000] type reference permission.permission_id%TYPE converted to integer
[2013-07-04 17:38:01] [00000] type reference permission.permission_id%TYPE converted to integer
[2013-07-04 17:38:01] [42601] ERROR: syntax error at or near "INSERT"
Where: SQL statement in PL/PgSQL function "permission_create" near line 9
How should I fix this? Is there a way to do this in multiple lines?
Solution:
CREATE FUNCTION permission_create(
IN method permission.permission_method % TYPE,
IN resource permission.permission_resource % TYPE
)
RETURNS TABLE (id INT)
AS
$BODY$
BEGIN
RETURN QUERY
INSERT INTO permission (permission_id, permission_method, permission_resource)
VALUES (DEFAULT, method, resource)
RETURNING permission_id;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;

Updateable CTE is supported from PostgreSQL 9.1.
you don't need use CTE (in your case)
postgres=# CREATE OR REPLACE FUNCTION fx()
RETURNS SETOF int AS $$
BEGIN
RETURN QUERY INSERT INTO taba(a) VALUES(1),(2)
RETURNING *;
RETURN;
END;
$$ LANGUAGE plpgsql;
CREATE FUNCTION
postgres=# select * from fx();
fx
----
1
2
(2 rows)

Related

PostgreSQL: function with array argument

For the first time I'm trying to create function in PostgreSQL:
This function must accept parameter with array type. Array contains sequence of biginteger values. Size of array not arbitrary, but known in advance.
create function get_total (cols ARRAY) returns biginteger AS
$BODY$
begin
// Some logics
end;
$BODY$
Usage in query
select
stats.value1,
stats.value2,
get_total(array_agg(ARRAY[stats.value2, stats.value1]))
from stats;
It returns error:
type cols[] does not exist
SQL state: 42704
When I run in Select only array_agg(ARRAY[stats.value2, stats.value1]), I see, that array created successfully. So the problem in function parameter.
What am I doing wrong?
You have to declare the parameter as bigint[], which reads an array of type bigint e.g.
CREATE OR REPLACE FUNCTION get_total (bigint[])
RETURNS bigint AS
$$
BEGIN
-- your fancy logic goes here
END;
$$ LANGUAGE plpgsql
Function call:
SELECT get_total(ARRAY[1111111111111,1111111111111]);
An elegant alternative is to declare the parameter as VARIADIC. Doing so you may call your function with multiple parameters,e.g.:
CREATE OR REPLACE FUNCTION get_total (VARIADIC bigint[])
RETURNS bigint AS
$$
BEGIN
-- your fancy logic goes here
END;
$$ LANGUAGE plpgsql;
Function call:
SELECT get_total(1111111111111,1111111111111,1111111111111);
Demo: db<>fiddle
The syntax cols ARRAY is the same as cols[] and means “an array with elements of type cols”. That's why you get that error message for the function definition.
If the element type is bigint, the function should be defined as
CREATE FUNCTION get_total(cols bigint ARRAY) RETURNS bigint

PostgreSQL ambiguous column reference after specifying column name

I have a function like this
CREATE OR REPLACE FUNCTION factors_apart_sa()
RETURNS TABLE(surf_area integer, sa_factor numeric) AS
$BODY$
BEGIN
RETURN QUERY SELECT factors_apart_sa.surf_area, factors_apart_sa.sa_factor FROM factors_apart_sa;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000;
After calling this function I get an error:
column reference "factors_apart_sa.surf_area" is ambiguous
How come is it still ambiguous if I have specified the table name.
Here is the table factors_apart_sa:
CREATE TABLE factors_apart_sa
(
factors_apar_sa_id bigserial NOT NULL,
surf_area integer,
sa_factor numeric(19,4) NOT NULL
)
Use a table alias:
CREATE OR REPLACE FUNCTION factors_apart_sa()
RETURNS TABLE(surf_area integer, sa_factor numeric) AS
$BODY$
BEGIN
RETURN QUERY SELECT f.surf_area, f.sa_factor FROM factors_apart_sa f;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
It is not a good idea to have the same names for a table and a function;
To call a function returnig set of rows place it in a FROM clause:
select f.*
from factors_apart_sa() f;

Rename the column name of a stored function

I've got a postgresql stored procedure, which is returning an integer.
When I call that function, the result is returned with the function name as column name.
For example the name of the function is: "add-person". The column name, when invoking the function, is "add-person".
Is there a way to make the database return the integer with a self-choosen column name? For example "id"?
I think it is pretty easy, but I currently miss the forests for the trees..
Edit:
What i'd missed to tell, is that the return value is a variable, like so:
CREATE OR REPLACE FUNCTION "scheme"."add-person"(arggivenname character varying, argfamilyname character varying) RETURNS integer AS
$BODY$
DECLARE
varResponse integer;
BEGIN
-- Operations before
INSERT INTO "scheme"."table"
(
given_name,
family_name
)
VALUES
(
arggivenname,
argfamilyname
)
RETURNING
"id"
INTO
varResponse;
-- Operations after
RETURN varResponse;
END;
$BODY$
LANGUAGE plpgsql VOLATILE COST 100;
You can us the AS statement for that. That means:
Select add-person() AS yourcolumnname
To have a named column from a function it is necessary to create a type and return that type from the function
create type mytype as (mycolumn integer);
create or replace function ri()
returns mytype as $$
select 1;
$$ language sql;
select * from ri();
mycolumn
----------
1
Edit
Or much simpler without the type creation as in #pozs comment:
create or replace function ri(out mycolumn integer)
as $$
select 1;
$$ language sql;

Pass UUID value as a parameter to the function

I have the table with some columns:
--table
create table testz
(
ID uuid,
name text
);
Note: I want to insert ID values by passing as a parameter to the function. Because I am generating the ID value
in the front end by using uuid_generate_v4(). So I need to pass the generated value to the function to insert
into the table
My bad try:
--function
CREATE OR REPLACE FUNCTION testz
(
p_id varchar(50),
p_name text
)
RETURNS VOID AS
$BODY$
BEGIN
INSERT INTO testz values(p_id,p_name);
END;
$BODY$
LANGUAGE PLPGSQL;
--EXECUTE FUNCTION
SELECT testz('24f9aa53-e15c-4813-8ec3-ede1495e05f1','Abc');
Getting an error:
ERROR: column "id" is of type uuid but expression is of type character varying
LINE 1: INSERT INTO testz values(p_id,p_name)
You need a simple cast to make sure PostgreSQL understands, what you want to insert:
INSERT INTO testz values(p_id::uuid, p_name); -- or: CAST(p_id AS uuid)
Or (preferably) you need a function, with exact parameter types, like:
CREATE OR REPLACE FUNCTION testz(p_id uuid, p_name text)
RETURNS VOID AS
$BODY$
BEGIN
INSERT INTO testz values(p_id, p_name);
END;
$BODY$
LANGUAGE PLPGSQL;
With this, a cast may be needed at the calling side (but PostgreSQL usually do better automatic casts with function arguments than inside INSERT statements).
SQLFiddle
If your function is that simple, you can use SQL functions too:
CREATE OR REPLACE FUNCTION testz(uuid, text) RETURNS VOID
LANGUAGE SQL AS 'INSERT INTO testz values($1, $2)';

Returning from a function with OUT parameter

I have an error, but I don't know what the problem is.
I want execute a function and return a value from a column filled in by the column default, a sequence - the equivalent of currval(sequence).
I use:
PostgreSQL 9.0
pgAdmin III
CREATE OR REPLACE FUNCTION name_function(in param_1 character varying
, out param_2 bigint)
AS
$$
BEGIN
INSERT INTO table (collumn_seq,param_1) VALUES (DEFAULT,param_1)
returning collumn_seq;
--where:collumn_seq reference a collumn serial..
END;
$$
LANGUAGE plpgsql VOLATILE;
I can create the function without error but when trying to execute, the following error is returned:
SELECT name_function('GHGHGH');
ERROR: The query has no destination for result data
It would work like this:
CREATE OR REPLACE FUNCTION name_function(param_1 varchar
, OUT param_2 bigint)
LANGUAGE plpgsql AS
$func$
BEGIN
INSERT INTO table (collumn_seq, param_1) -- "param_1" also the column name?
VALUES (DEFAULT, param_1)
RETURNING collumn_seq
INTO param2;
END
$func$;
Normally, you would add a RETURN statement, but with OUT parameters, this is optional.
Refer to the manual for more details:
Returning from a function
Executing a Query with a Single-row Result
The simple case can be covered with a plain SQL function.
And you can omit the target column that shall get its DEFAULT value.
And you can just as well use a RETURNS clause in this case:
CREATE OR REPLACE FUNCTION name_function(param_1 varchar)
RETURNS bigint
LANGUAGE sql AS
$func$
INSERT INTO table (param_1) -- "param_1" also the column name?
VALUES (param_1)
RETURNING collumn_seq;
$func$;