Postgres INSERT IF parameter is not null - postgresql

I have a function which takes a parameter, and I want to only insert that param into a table if it's not null. I'm trying something like this:
CREATE OR REPLACE FUNCTION app.some_function(
my_param integer)
RETURNS void
LANGUAGE 'sql'
COST 100
VOLATILE
AS $BODY$
INSERT INTO app.myTable(something)
VALUES(my_param)
ON CONFLICT(something) DO
UPDATE
SET --someConflictLogic
WHERE my_param <> '' AND my_param IS NOT NULL;
$BODY$;
I was hoping the WHERE clause here would cover me, but it's not the case. When I call this function with my_param as NULL, I get:
null value in column "something" violates not-null constraint
So it looks like it's still trying to insert it. How can I correct this condition?

You can turn the insert ... values () into aninsert ... select` with a where clause attached:
CREATE OR REPLACE FUNCTION app.some_function(my_param integer)
RETURNS void
LANGUAGE sql
VOLATILE
AS
$BODY$
INSERT INTO app.myTable(something)
select my_param
where my_param IS NOT NULL
and my_param <> ''
ON CONFLICT(something) DO
UPDATE
SET --someConflictLogic;
$BODY$;
The where clause you used only applies to the DO UPDATE part, not the "primary" insert part.
Unrelated, but: the name of the function language is an identifier. It should be quoted.

You may use IF..THEN and change to plpgsql function
CREATE OR REPLACE FUNCTION app.some_function(
my_param integer)
RETURNS void
LANGUAGE plpgsql
COST 100
VOLATILE
AS $BODY$
IF NULLIF(my_param,'') IS NOT NULL THEN
INSERT INTO app.myTable(something)
VALUES(my_param)
ON CONFLICT(something) DO
UPDATE
SET --someConflictLogic;
END IF;
$BODY$;

Related

Create a stored procedure to Delete Records postgres

I have created a function to delete multiple records.In our table contain id as type uuid.
We get the input is like array of ids.
CREATE OR REPLACE FUNCTION public.deletetVersion(item_list uuid[])
RETURNS TABLE(id uuid[])
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
ROWS 1000
AS $BODY$
BEGIN
RETURN QUERY
DELETE FROM version WHERE id = ANY(item_list);
END;
$BODY$;
SELECT * from deletetVersion(Array['b6ad1912-e4f1-4419-831a-c70df89ffd63','877898f0-2f3f-4890-a658-898e35ffee3a'])
But i got an error like:
Anyone please help me
ERROR: function deletetversion(text[]) does not exist
it is because the
Array['b6ad1912-e4f1-4419-831a-c70df89ffd63','877898f0-2f3f-4890-a658-898e35ffee3a']
is treated as text[]
try the following
Array['b6ad1912-e4f1-4419-831a-c70df89ffd63'::uuid,'877898f0-2f3f-4890-a658-898e35ffee3a'::uuid]
as a parameter to your function
for example
CREATE OR REPLACE FUNCTION public.test_uuid(item_list uuid[])
RETURNS TABLE(id uuid[])
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
ROWS 1000
AS $BODY$
BEGIN
RETURN QUERY
SELECT item_list;
END;
$BODY$;
SELECT * from test_uuid(Array['b6ad1912-e4f1-4419-831a-c70df89ffd63'::uuid])
In case of deletion
CREATE OR REPLACE FUNCTION public.test_uuid(item_list uuid[])
RETURNS VOID
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
ROWS 1000
AS $BODY$
BEGIN
RETURN QUERY
DELETE from tableName WHERE id = ANY(item_list);
END;
$BODY$;
Your function should return either setof uuid - i.e. a table of uuid-s - or uuid[]. I would prefer the first. You do not need PL/pgSQL, plain SQL is enough. So the function is:
create or replace function public.deletetVersion(item_list uuid[])
returns setof uuid language 'sql' as
$$
delete from version where id = any(item_list) returning id;
$$;
The version returning an array is a bit more complex:
create or replace function public.deletetVersion(item_list uuid[])
returns uuid[] language 'sql' as
$$
with t(d_id) as
(
delete from version where id = any(item_list) returning id
)
select array_agg(d_id) from t;
$$;
And - as #Ibrahimshamma says - you may need to cast the argument to uuid[].

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)';

Return ID of last inserted row in PostgreSQL with RETURNING clause

I've got a pretty simple function defined like so:
CREATE OR REPLACE FUNCTION create_new_order(....) RETURNS integer AS
$BODY$
BEGIN
PERFORM add_points_to_usage(client_id_p, date_in_p, total_points_p);
INSERT INTO orders (...) VALUES (...)
RETURNING ident;
END;
$BODY$ LANGUAGE plpgsql;
Where I'm struggling is how to actually RETURN the value stored in the ident field back via the RETURNING clause. I've tried setting the value to a variable but that either doesn't work or I'm just messing up the syntax.
You're missing the variable declaration, the INTO clause and the final RETURN:
CREATE OR REPLACE FUNCTION create_new_order(....) RETURNS integer AS
$BODY$
DECLARE
var_ident int;
BEGIN
PERFORM add_points_to_usage(client_id_p, date_in_p, total_points_p);
INSERT INTO orders (...) VALUES (...)
RETURNING ident INTO var_ident;
RETURN var_ident;
END;
$BODY$ LANGUAGE plpgsql;