PostgreSQL - how to use equals for null in routine - postgresql

I have a routine with 4 parameters passed in. Sometimes the last parameter "membership_type " is null but when I use equals it does not return records with null value, it does work if I use "is null" but looking for advice how to make sure both work in the same routine:
create or replace function fitnessone_master.get_location_cancellation_count(club_number double precision, date date, member_profile character varying, membership_type character varying) returns integer
language plpgsql
as $$
declare
member_count integer;
begin
return (select count(distinct a.agreement_number) as member_count
from fitnessone_master.cancelled_accounts a
where cancel_date = get_location_cancellation_count.date
and a.club_number = get_location_cancellation_count.club_number
and a.member_profile = get_location_cancellation_count.member_profile
and a.membership_type = get_location_cancellation_count.membership_type);
end;
$$;

Instead of using = x, which will never match NULL, you can use IS NOT DISTINCT FROM x:
create or replace function fitnessone_master.get_location_cancellation_count(club_number double precision, date date, member_profile character varying, membership_type character varying) returns integer
language plpgsql
as $$
declare
member_count integer;
begin
return (select count(distinct a.agreement_number) as member_count
from fitnessone_master.cancelled_accounts a
where cancel_date = get_location_cancellation_count.date
and a.club_number = get_location_cancellation_count.club_number
and a.member_profile = get_location_cancellation_count.member_profile
and a.membership_type is not distinct from get_location_cancellation_count.membership_type);
end;
$$;

Related

In clause in postgres

Need Output from table with in clause in PostgreSQL
I tried to make loop or ids passed from my code. I did same to update the rows dynamically, but for select I m not getting values from DB
CREATE OR REPLACE FUNCTION dashboard.rspgetpendingdispatchbyaccountgroupidandbranchid(
IN accountgroupIdCol numeric(8,0),
IN branchidcol character varying
)
RETURNS void
AS
$$
DECLARE
ArrayText text[];
i int;
BEGIN
select string_to_array(branchidcol, ',') into ArrayText;
i := 1;
loop
if i > array_upper(ArrayText, 1) then
exit;
else
SELECT
pd.branchid,pd.totallr,pd.totalarticle,pd.totalweight,
pd.totalamount
FROM dashboard.pendingdispatch AS pd
WHERE
pd.accountgroupid = accountgroupIdCol AND pd.branchid IN(ArrayText[i]::numeric);
i := i + 1;
end if;
END LOOP;
END;
$$ LANGUAGE 'plpgsql' VOLATILE;
There is no need for a loop (or PL/pgSQL actually)
You can use the array directly in the query, e.g.:
where pd.branchid = any (string_to_array(branchidcol, ','));
But your function does not return anything, so obviously you won't get a result.
If you want to return the result of that SELECT query, you need to define the function as returns table (...) and then use return query - or even better make it a SQL function:
CREATE OR REPLACE FUNCTION dashboard.rspgetpendingdispatchbyaccountgroupidandbranchid(
IN accountgroupIdCol numeric(8,0),
IN branchidcol character varying )
RETURNS table(branchid integer, totallr integer, totalarticle integer, totalweight numeric, totalamount integer)
AS
$$
SELECT pd.branchid,pd.totallr,pd.totalarticle,pd.totalweight, pd.totalamount
FROM dashboard.pendingdispatch AS pd
WHERE pd.accountgroupid = accountgroupIdCol
AND pd.branchid = any (string_to_array(branchidcol, ',')::numeric[]);
$$
LANGUAGE sql
VOLATILE;
Note that I guessed the data types for the columns of the query based on their names. You have to adjust the line with returns table (...) to match the data types of the select columns.

PSQLException: ERROR: syntax error at or near "test"

I'm getting the same error as in the title:
CREATE OR REPLACE FUNCTION func(param varchar) RETURNS varchar AS
'BEGIN
LOCK public.routes;
return (SELECT * FROM public.routes WHERE guid = 'test');
END;' LANGUAGE plpgsql
What might be the problem? I can execute the same in console and it's gonna work.
You need to escape single quotes embedded in string literals by doubling them:
CREATE OR REPLACE FUNCTION func(param varchar) RETURNS varchar AS
'BEGIN
LOCK public.routes;
return (SELECT * FROM public.routes WHERE guid = ''test'');
END;' LANGUAGE plpgsql
That's the reason why people usually use dollar quoting for the body of functions:
CREATE OR REPLACE FUNCTION func(param varchar) RETURNS varchar AS
$body$
BEGIN
LOCK public.routes;
return (SELECT * FROM public.routes WHERE guid = 'test');
END;
$body$
LANGUAGE plpgsql
However, even if you get the syntax right: the function will not work. It is defined to return a single (scalar) value of type varchar but it returns the all rows from the table routes. If you want to return multiple rows, you need to define the function as returns setof or returns table. In your case returns setof routes would be applicable:
CREATE OR REPLACE FUNCTION func(param varchar)
RETURNS setof public.routes
AS
$body$
BEGIN
LOCK public.routes;
return (SELECT * FROM public.routes WHERE guid = 'test');
END;
$body$
LANGUAGE plpgsql
If you intend to return the value of a single column of a single row (assuming that guid is defined as PK or unique), then indeed returns varchar would work. But then you should change the select statement to select some_column from .. or something similar

function does not exists in postgreSQL .. Why ?

Need your help please , can't understand why i got the following error , i am not a professional postgresql developer ..
As you can see the function created , so why the function not exist occurred ?
create or replace function loginAttempt (u_email character varying, u_password character varying, date_time timestamptz, OUT attempt smallint) returns smallint AS $$
BEGIN
INSERT INTO login_attempts (typed_password, date_time, attempt_nu, email) VALUES (u_password, date_time, attempt_nu, email);
IF attempt = 3 THEN INSERT INTO warnings (u_email,u_password) VALUES (u_email,u_password);
END IF;
END;
$$ LANGUAGE plpgsql;
select loginattempt ('Jon.Jones88#gmail.com','+_#kjhfdb987', now(), 1);
ERROR: function loginattempt(unknown, unknown, timestamp with time zone, integer) does not exist
LINE 1: select loginattempt ('Jon.Jones88#gmail.com','+_#kjhfdb987',...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
SQL state: 42883
Character: 8
You have defined the last parameter as an OUT parameter, that means you can't pass a value for it.
You need to use:
select loginattempt ('Jon.Jones88#gmail.com','+_#kjhfdb987', now());
As you are not writing to the parameter attempts I don't see a reason to define it as an out parameter to begin with. You can simply return the value if you need it:
create or replace function loginAttempt (u_email character varying, u_password character varying, u_date_time timestamptz, u_attempt smallint)
returns smallint
AS $$
BEGIN
INSERT INTO login_attempts (typed_password, date_time, attempt_nu, email)
VALUES (u_password, u_date_time, u_attempt, u_email);
IF u_attempt = 3 THEN
INSERT INTO warnings (u_email,u_password) VALUES (u_email,u_password);
END IF;
return u_attempt;
END;
$$ LANGUAGE plpgsql;
As the value 1 is assumed to be an integer, you need to cast that value when calling the function:
select loginattempt ('Jon.Jones88#gmail.com','+_#kjhfdb987', now(), 1::smallint);
Online example: https://rextester.com/YNIQ55561

PostgreSQL function does not return a value

-- I can not understand where the error
CREATE OR REPLACE FUNCTION get_person_membership (IN person_urn CHARACTER VARYING)
RETURNS TEXT AS
$BODY$
DECLARE
result text;
urn ALIAS FOR $1;
BEGIN
SELECT INTO result pers.mx_groupmember FROM mt_person AS pers, mxt_recordheader AS rech
WHERE rech.primaryurn = 'urn'
AND rech.entitytype = 'person'
AND rech.logicalserverprefix = 'EA'
AND rech.id = pers.id;
RETURN result;
END;
$BODY$
LANGUAGE plpgsql
VOLATILE
COST 100
i simplified your query:
For input you can use $1, this goes to direct your condition.
You can return direct your result if you dont need anywhere else.
select * from get_person_membership('something');
CREATE OR REPLACE FUNCTION get_person_membership (IN person_urn CHARACTER VARYING)
RETURNS TEXT AS
$BODY$
BEGIN
RETURN (select pers.mx_groupmember --returns single value
FROM mt_person AS pers, mxt_recordheader AS rech
WHERE rech.primaryurn = $1 --input value from person_urn
AND rech.entitytype = 'person'
AND rech.logicalserverprefix = 'EA'
AND rech.id = pers.id);
END;
$BODY$
LANGUAGE plpgsql
VOLATILE
COST 100
No need for PL/pgSQL, a simple SQL function will do:
CREATE OR REPLACE FUNCTION get_person_membership (IN person_urn CHARACTER VARYING)
RETURNS TEXT AS
$BODY$
SELECT pers.mx_groupmember
FROM mt_person AS pers
JOIN mxt_recordheader AS rech ON rech.id = pers.id
WHERE rech.primaryurn = person_urn --<< input parameter
AND rech.entitytype = 'person'
AND rech.logicalserverprefix = 'EA';
$BODY$
LANGUAGE sql;

Can I make a plpgsql function return an integer without using a variable?

Something like this:
CREATE OR REPLACE FUNCTION get(param_id integer)
RETURNS integer AS
$BODY$
BEGIN
SELECT col1 FROM TABLE WHERE id = param_id;
END;
$BODY$
LANGUAGE plpgsql;
I would like to avoid a DECLARE just for this.
Yes you can. There are a number of ways.
1) RETURN (SELECT ...)
CREATE OR REPLACE FUNCTION get_1(_param_id integer)
RETURNS integer
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN _param_id;
-- Or:
-- RETURN (SELECT col1 FROM tbl WHERE id = _param_id);
END
$func$;
2) Use an OUT or INOUT parameter
CREATE OR REPLACE FUNCTION get_2(_param_id integer, OUT _col1 integer)
-- RETURNS integer -- is optional noise in this case
LANGUAGE plpgsql AS
$func$
BEGIN
SELECT INTO _col1 col1 FROM tbl WHERE id = _param_id;
-- also valid, but discouraged:
-- _col1 := col1 FROM tbl WHERE id = _param_id;
END
$func$;
More in the manual here.
3) (Ab)use IN parameter
Since Postgres 9.0 you can also use input parameters as variables. The release notes for 9.0:
An input parameter now acts like a local variable initialized to the passed-in value.
CREATE OR REPLACE FUNCTION get_3(_param_id integer)
RETURNS integer
LANGUAGE plpgsql AS
$func$
BEGIN
SELECT INTO _param_id col1 FROM tbl WHERE id = _param_id;
RETURN _param_id;
-- Also vlaid, but discouraged:
-- $1 := col1 FROM tbl WHERE id = $1;
-- RETURN $1;
END
$func$;
Variants 2) and 3) do use a variable implicitly, but you don't have to DECLARE one explicitly (as requested).
4) Use a DEFAULT value with an INOUT parameter
This is a bit of a special case. The function body can be empty.
CREATE OR REPLACE FUNCTION get_4(_param_id integer, INOUT _col1 integer = 123)
RETURNS integer
LANGUAGE plpgsql AS
$func$
BEGIN
-- You can assign some (other) value to _col1:
-- SELECT INTO _col1 col1 FROM tbl WHERE id = _param_id;
-- If you don't, the DEFAULT 123 will be returned.
END
$func$;
INOUT _col1 integer = 123 is short notation for INOUT _col1 integer DEFAULT 123. See:
The forgotten assignment operator "=" and the commonplace ":="
5) Use a plain SQL function instead
CREATE OR REPLACE FUNCTION get_5(_param_id integer)
RETURNS integer
LANGUAGE sql AS
'SELECT col1 FROM tbl WHERE id = _param_id';
Or use use param reference $1 instead of param name.
Variant 5) one uses plain single quotes for the function body. All the same. See:
What are '$$' used for in PL/pgSQL
Insert text with single quotes in PostgreSQL
db<>fiddle here - demonstrating all (incl. call)