Postgres mistakes parameter for column - postgresql

I am new to Postgres DBs, and I am trying to write a function (like a stored procedure) to all inserting a user into my database. I know I must be missing something obvious, but I keep getting an error in the code shown where Postgres says { error: column "p_organizationsid" does not exist }. This is the snippet of code that appears to be causing the problem.
CREATE OR REPLACE FUNCTION userupsertget(
p_id uuid,
p_username character varying,
p_organizationid uuid,
p_organizationsid character varying,
p_lastname character varying,
p_firstname character varying,
p_middleinitial character varying,
p_emailaddress character varying,
p_sid character varying,
p_languageid integer,
p_forcepasswordreset bit,
p_salt character varying,
p_hash character varying,
p_statusid uuid,
p_createdby uuid,
p_modifiedby uuid,
p_lastsessionuguid uuid,
p_roleids uuid[],
p_applicationid uuid)
RETURNS SETOF users
LANGUAGE 'plpgsql'
COST 100
VOLATILE
ROWS 1000
AS $BODY$
BEGIN
DO
$do$
DECLARE establishedOrgID uuid;
BEGIN
SELECT org.id FROM organization AS org
WHERE org.sid = p_organizationsid
OR org.id = p_organizationid;
IF EXISTS (SELECT 1 FROM users WHERE id = p_id) THEN
--update statement;
UPDATE users
SET username = p_username,
lastname = p_lastname,
firstname = p_firstname,
middleinitial = p_middleinitial,
emailaddress = p_emailaddress,
sid = p_sid,
languageid = p_languageid,
forcepasswordreset = p_forcepasswordreset,
statusid = p_statusid,
datemodified = current_timestamp,
createdby = p_createdby,
modifiedby = p_modifiedby,
lastsessionguid = p_lastsessionguid
WHERE id = p_id;
IF EXISTS (SELECT 1 FROM users WHERE id = p_id AND statusid <> p_statuid) THEN
UPDATE users SET statusid = p_statusid, datestatusmodified = current_timestamp WHERE id = p_id;
END IF;
ELSE
INSERT INTO users (id, organizationid, username, lastname, firstname, middleinitial,
emailaddress, sid, languageid, forcepasswordreset, statusid, datecreated,
datemodified, createdby, modifiedby, lastsessionguid)
SELECT p_id, establishedOrgID, p_username, p_lastname, p_firstname, p_middleinitial, p_emailaddress, p_sid,
p_languageid, p_forcepasswordreset, p_statusid, current_timestamp, current_timestamp,
p_createdby, p_modifiedby, p_lastsessionuguid
FROM users
WHERE id = p_id;
-- DECLARE newid uuid := LASTVAL();
INSERT INTO users (id, userid, roleid, applicationid, startdate, enddate, createdby, modifiedBy)
SELECT LASTVAL(), roleid, p_applicationid, current_timestamp, current_timestamp, p_createdby, p_modifiedby
FROM UNNEST (p_roleids) AS roleids;
END IF;
END
$do$;
RETURN QUERY
SELECT usr.*, org.uselogin
FROM users AS usr
INNER JOIN organization AS org On org.id = usr.organizationid
WHERE id = p_id;
END;
$BODY$;

As you can see in the PostgreSQL documentation about Creating a function: https://www.postgresql.org/docs/9.1/sql-createfunction.html
you should get better luck if you replace your parameter's name by $n where n is the number of the function parameter:
CREATE FUNCTION add(integer, integer) RETURNS integer
AS 'select $1 + $2;'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
or...
CREATE FUNCTION check_password(uname TEXT, pass TEXT)
RETURNS BOOLEAN AS $$
DECLARE passed BOOLEAN;
BEGIN
SELECT (pwd = $2) INTO passed
FROM pwds
WHERE username = $1;
RETURN passed;
END;
$$ LANGUAGE plpgsql
SECURITY DEFINER
-- Set a secure search_path: trusted schema(s), then 'pg_temp'.
SET search_path = admin, pg_temp;
Now, if you wish to continue using parameter names, you should declare them as alias:
CREATE or REPLACE FUNCTION data_ctl(opcao char, fdata date, fhora time) RETURNS char(10) AS $$
DECLARE
opcao ALIAS FOR $1;
vdata ALIAS FOR $2;
vhora ALIAS FOR $3;
retorno char(10);
BEGIN
IF opcao = 'I' THEN
insert into datas (data, hora) values (vdata, vhora);
retorno := 'INSERT';
END IF;
IF opcao = 'U' THEN
update datas set data = vdata, hora = vhora where data='1995-11-01';
retorno := 'UPDATE';
END IF;
IF opcao = 'D' THEN
delete from datas where data = vdata;
retorno := 'DELETE';
ELSE
retorno := 'NENHUMA';
END IF;
RETURN retorno;
END;
$$
LANGUAGE plpgsql;
--select data_ctl('I','1996-11-01', '08:15');
select data_ctl('U','1997-11-01','06:36');
select data_ctl('U','1997-11-01','06:36');

Related

How to do postgresql select query funciton using parameter?

I want to create a postgresql funciton that returns records. But if I pass an id parameter, it should be add in where clause. if I do not pass or null id parameter, where clasuse will not add the query.
CREATE OR REPLACE FUNCTION my_func(id integer)
RETURNS TABLE (type varchar, total bigint) AS $$
DECLARE where_clause VARCHAR(200);
BEGIN
IF id IS NOT NULL THEN
where_clause = ' group_id= ' || id;
END IF ;
RETURN QUERY SELECT
type,
count(*) AS total
FROM
table1
WHERE
where_clause ???
GROUP BY
type
ORDER BY
type;
END
$$
LANGUAGE plpgsql;
You can either use one condition that takes care of both situations (then you don't need PL/pgSQL to begin with):
CREATE OR REPLACE FUNCTION my_func(p_id integer)
RETURNS TABLE (type varchar, total bigint)
AS $$
SELECT type,
count(*) AS total
FROM table1
WHERE p_id is null or group_id = p_id
GROUP BY type
ORDER BY type;
$$
LANGUAGE sql;
But an OR condition like that is typically not really good for performance. The second option you have, is to simply run two different statements:
CREATE OR REPLACE FUNCTION my_func(p_id integer)
RETURNS TABLE (type varchar, total bigint)
AS $$
begin
if (p_id is null) then
return query
SELECT type,
count(*) AS total
FROM table1
GROUP BY type
ORDER BY type;
else
return query
SELECT type,
count(*) AS total
FROM table1
WHERE group_id = p_id
GROUP BY type
ORDER BY type;
end if;
END
$$
LANGUAGE plgpsql;
And finally you can build a dynamic SQL string depending the parameter:
CREATE OR REPLACE FUNCTION my_func(p_id integer)
RETURNS TABLE (type varchar, total bigint)
AS $$
declare
l_sql text;
begin
l_sql := 'SELECT type, count(*) AS total FROM table1 '
if (p_id is not null) then
l_sql := l_sql || ' WHERE group_id = '||p_id;
end if;
l_sql := l_sql || ' GROUP BY type ORDER BY type';
return query execute l_sql;
end;
$$
LANGUAGE plpgsql;
Nothing is required just to use the variable as it is for more info please refer :plpgsql function parameters

postgresql procedure multiple select statement results as output

How do we get multiple result sets from Postgresql procedure. Below is the Procedure i created which is not working. I know that this is not how it works in Postgresql but unable to find the required answer anywhere. After this i need to get these multiple resultsets in Java JDBC.
CREATE OR REPLACE PROCEDURE public.validate_user_login(
a_username character varying,
a_password character varying,
a_ip character varying,
a_uuid character varying,
a_appid integer,
a_osname character varying,
a_osversion character varying,
a_devicemake character varying,
a_devicemodel character varying,
a_devicelat numeric,
a_devicelong numeric
)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
v_tenant_id INTEGER;
v_user_id INTEGER;
v_tenant_device_id INTEGER;
statuscode INTEGER;
BEGIN
select user_id , tenant_id into v_tenant_id , v_user_id
from public.users
where username = a_username
and password = a_password;
if v_tenant_id > 0 AND v_user_id > 0
then
statuscode := 1;
select tenant_device_id into v_tenant_device_id from tenant_devices
where tenant_id = v_tenant_id
and uuid = a_uuid;
insert into login_history (user_id , app_id , geo_lat , geo_long ,ip_address , tenant_device_id)
VALUES (v_user_id, a_appid,a_devicelat ,a_devicelong , a_ip, v_tenant_device_id );
else
statuscode := -1;
end if;
select user_id , username , email , phone_no, alt_phone_no
from public.users
where username = a_username
and password = a_password
limit 1;
select role_id from
public.user_roles
where user_id = v_user_id;
select statuscode;
END
$BODY$;

Issue with dynamic sql

Hi every one I have multiple spatial tables That I want to control, so that I created a table where I will store the name of the operation applied on my layers tables(insert,update or delete), operation time and the team who did it, number of spatial tables created.
My script table
CREATE TABLE public.monitoring_table
(
operation character(1) COLLATE pg_catalog."default",
operat_ime timestamp without time zone,
userid text COLLATE pg_catalog."default",
dc_team text COLLATE pg_catalog."default",
number_pts_created integer,
id integer NOT NULL DEFAULT nextval('monitoring_table_id_seq'::regclass),
CONSTRAINT monitoring_table_pkey PRIMARY KEY (id)
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE public.monitoring_table
OWNER to postgres;
after that I stored all the teams that I have on my table :
insert into monitoring_table (dc_team) values ('abdoulhassan');
insert into monitoring_table (dc_team) values ('abdoulei');
insert into monitoring_table (dc_team) values ('danis');
insert into monitoring_table (dc_team) values ('david');
insert into monitoring_table (dc_team) values ('joseph');
To calculate the number of spatial tables created, I executed this function :
My counting function :
DROP FUNCTION get_dc_team_counting();
CREATE OR REPLACE FUNCTION get_dc_team_counting()
RETURNS bigint AS
$func$
DECLARE
dc_team text;
_tbl_pattern text;
_schema text = 'sige';
_tb_name information_schema.tables.table_name%TYPE;
_tc bigint;
BEGIN
FOR _tb_name IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = _schema
AND table_name ~ _tbl_pattern
LOOP
EXECUTE format('SELECT count(*) FROM %I.%I where id= 583', _schema, _tb_name)
INTO _tc;
return _tc;
END LOOP;
END
$func$ LANGUAGE plpgsql
To get the team I executed this function :
CREATE OR REPLACE FUNCTION get_team()
RETURNS text AS -- or whatever you want to return
$func$
DECLARE
dc_team text;
_tbl_pattern text;
_schema text = 'public';
_tb_name information_schema.tables.table_name%TYPE; -- currently varchar
_tc text;
BEGIN
FOR _tb_name IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = _schema
AND table_name ~ _tbl_pattern -- see below!
LOOP
EXECUTE format('SELECT dc_team FROM %I.%I where id = 26', _schema, _tb_name)
INTO _tc;
return _tc;
END LOOP;
END
$func$ LANGUAGE plpgsql;
In my where clause I want to get dynamically the value of the ID. I don't want to give it manually in the function. I don't see how to do it.
Now I created a trigger function to be able to update my table if a row was inserted, updated or deleted. I did it this way :
CREATE OR REPLACE FUNCTION process_monitoring() RETURNS TRIGGER AS $monitoring$
BEGIN
IF (TG_OP = 'DELETE') THEN
update monitoring_table set operation = 'D', operat_ime = now(), userid = user ,dc_team = OLD.dc_team, number_pts_created = get_dc_team_counting() where dc_team = get_team();
RETURN OLD;
ELSIF (TG_OP = 'UPDATE') THEN
update monitoring_table set operation = 'U',operat_ime = now(),userid = user , dc_team = NEW.dc_team, number_pts_created = get_dc_team_counting() where dc_team = get_team();
RETURN NEW;
ELSIF (TG_OP = 'INSERT') THEN
update monitoring_table set operation = 'I', operat_ime = now(), userid = user, dc_team = NEW.dc_team, number_pts_created = get_dc_team_counting() where dc_team = get_team();
RETURN NEW;
END IF;
RETURN NULL;
END;
$monitoring$ LANGUAGE plpgsql;
CREATE TRIGGER monitoring
AFTER INSERT OR UPDATE OR DELETE ON sige.valve
FOR EACH ROW EXECUTE PROCEDURE process_monitoring();
In my previous functions I used known values of ids in the where clauses, but when I try to insert or update a value on the concerned table I get this error :
the control attempted it's end without return
CONTEXT: fonction PL/pgsql get_team()
instruction SQL « update monitoring_table set operation = 'U',operat_ime = now(),userid = user , dc_team = NEW.dc_team, number_pts_created = get_dc_team_counting() where dc_team = get_team() »
fonction PL/pgsql process_monitoring(), ligne 10 à instruction SQL
If you have any idea about the origin of the error and how to get dynamically a value of a field and put it in the where clause tell me please.
I'm a newbie and I'm struggling, any assistance would be warmly appreciated.
I'm using PostgreSQL.

How to return setof records from function?

I'm trying to create a function which will return setof record. I want to use the function as follows:
SELECT city_name FROM set_city(1, 1, 'ExampleName');
My function:
CREATE OR REPLACE FUNCTION set_city(_city_id integer, _country_id integer, _city_name varchar)
RETURNS SETOF RECORD
LANGUAGE plpgsql
as $$
DECLARE
result record;
BEGIN
IF EXISTS (SELECT 1 FROM geo_cities gc WHERE gc.id = _city_id)
THEN
UPDATE geo_cities
SET country_id = _country_id, city_name = _city_name
WHERE id = _city_id
RETURNING * INTO result;
ELSE
INSERT INTO geo_cities(id, country_id, city_name)
VALUES (_city_id, _country_id, _city_name)
RETURNING * INTO result;
END IF;
-- It's wrong
RETURN QUERY SELECT result;
END;
$$
What should I change?
You could change the return statement:
...
-- It's wrong
-- RETURN QUERY SELECT result;
RETURN NEXT result; -- that's good
...
However, a column definition list is required for functions returning "record", so you would have to add it in every query:
SELECT city_name FROM set_city(1, 1, 'ExampleName')
AS (id int, country_id int, city_name text);
In fact the function returns a single row of the type geo_cities and you do not need setof:
DROP FUNCTION set_city(_city_id integer, _country_id integer, _city_name varchar);
CREATE OR REPLACE FUNCTION set_city(_city_id integer, _country_id integer, _city_name varchar)
RETURNS geo_cities
LANGUAGE plpgsql
as $$
DECLARE
result geo_cities;
BEGIN
IF EXISTS (SELECT 1 FROM geo_cities gc WHERE gc.id = _city_id)
THEN
UPDATE geo_cities
SET country_id = _country_id, city_name = _city_name
WHERE id = _city_id
RETURNING * INTO result;
ELSE
INSERT INTO geo_cities(id, country_id, city_name)
VALUES (_city_id, _country_id, _city_name)
RETURNING * INTO result;
END IF;
RETURN result;
END;
$$;
SELECT city_name FROM set_city(1, 1, 'ExampleName');
Note that you can get the same functionality in a single SQL statement:
INSERT INTO geo_cities(id, country_id, city_name)
VALUES (1, 1, 'ExampleName')
ON CONFLICT (id) DO UPDATE SET
country_id = excluded.country_id,
city_name = excluded.city_name
RETURNING *;

Use Variable in a select statement in a Function

Is it possible to declare a variable from another variable that was already declared in a function?
Example of what I am expecting below..
CREATE OR REPLACE FUNCTION insertRecord
(
a varchar (100),
b varchar(100),
c varchar(100)
)
RETURNS TEXT AS $$
DECLARE
orgId := (select id from org)
projectId := select id from project where orgId = orgId
BEGIN
return projectId;
END;
$$ LANGUAGE plpgsql;
First declare the variables. And rename the orgId to avoid ambiguity with the column name.
CREATE OR REPLACE FUNCTION insertRecord
(
a varchar (100),
b varchar(100),
c varchar(100)
)
RETURNS TEXT AS $$
DECLARE
orgId_var integer;
projectId varchar;
BEGIN
orgId_var := (select id from org limit 1);
projectId := (select id from project where orgId = orgId_var);
return projectId;
END;
$$ LANGUAGE plpgsql;
Perhaps you just want to use a join instead? Something along these lines (but with more filters added so as not to return multiple rows):
CREATE OR REPLACE FUNCTION insertRecord(
a varchar (100),
b varchar(100),
c varchar(100)
)
RETURNS TEXT AS $$
DECLARE
v_project_id project.id%TYPE;
BEGIN
SELECT p.id
INTO v_project_id
FROM project p
JOIN org o ON (o.id = p.org_id);
RETURN v_project_id;
END;
$$ LANGUAGE plpgsql;