How can i combine multiple functions into one in postgresql? - postgresql

I wrote a series of functions updating a progress column in my project, I wonder if this can be combined into a single function. I tried it, using SELECT * FROM schema.table; IF, ELSE IF ... THEN UPDATE column SET progress = xx however all i got was syntax errors on various lines, with which i couldn't figure out what i did wrong.
I would appreciate ideas as to what i did wrong or how i could achieve a single function in a different way, THANKS GUYS :)
This is the code, that worked, but i want to shorten:
CREATE OR REPLACE FUNCTION progress_update25() RETURNS void AS $$
BEGIN
UPDATE schema.table SET progress = 25 WHERE on_side_inspection = 'done';
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION progress_update50() RETURNS void AS $$
BEGIN
UPDATE schema.table SET progress = 50 WHERE statement = 'requested' OR statement = 'received';
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION progress_update75() RETURNS void AS $$
BEGIN
UPDATE schema.table SET progress = 75 WHERE
permit_01 = 'requested' OR permit_01 = 'permitted' OR permit_01 = 'n/a'
AND permit_02 = 'requested' OR permit_02 = 'permitted' OR permit_02 = 'n/a'
AND permit_03 = 'requested' OR permit_03 = 'permitted' OR permit_03 = 'n/a'
AND permit_04 = 'requested' OR permit_04 = 'permitted' OR permit_04 = 'n/a';
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION progress_update90() RETURNS void AS $$
BEGIN
UPDATE schema.table SET progress = 90 WHERE permits_complete = 'complete';
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION progress_update100() RETURNS void AS $$
BEGIN
UPDATE schema.table SET progress = 100 WHERE documentation = 'submitted';
END;
$$ LANGUAGE plpgsql;
This is the code, thats not working:
CREATE OR REPLACE FUNCTION progress_update() RETURNS void AS $$
BEGIN
SELECT * FROM schema.table;
IF on_side_inspection = 'done'
THEN UPDATE table SET progress = 25;
ELSE IF statement = 'requested' OR statement = 'received'
THEN UPDATE table SET progress = 50;
ELSE IF permit_01 = 'requested' OR permit_01 = 'permitted' OR permit_01 = 'n/a'
AND permit_02 = 'requested' OR permit_02 = 'permitted' OR permit_02 = 'n/a'
AND permit_03 = 'requested' OR permit_03 = 'permitted' OR permit_03 = 'n/a'
AND permit_04 = 'requested' OR permit_04 = 'permitted' OR permit_04 = 'n/a'
THEN UPDATE table SET progress = 75;
ELSE IF permits_complete = 'complete'
THEN UPDATE table SET progress = 90;
ELSE IF documentation = 'submitted'
THEN UPDATE table SET progress = 100;
END IF;
END;
$$ LANGUAGE plpgsql;

There are lot of issues - undeclared variables, missing INTO clause or badly used IF statement:
You do:
IF ... THEN
ELSE IF THEN
END IF;
It can work in some other languages, but not in Postgres. It should to be
IF ... THEN
ELSEIF ... THEN
END IF;

Related

postgres functions and transactions with BEGIN and blocks

I have some questions about how postgres functions and transactions work. I am beginners to transactions and functions . please help me to understand the following code.
Currently my function looks like this:
CREATE OR REPLACE FUNCTION what_do_i_do(
arg_i jsonb
)
RETURNS json
LANGUAGE plpgsql
AS
$function$
DECLARE
rcd RECORD;
msg text;
error json;
b boolean;
i integer;
response json;
BEGIN
--block 1
i = arg_i->>'i';
--block 2
a_i = arg_i->>'a_i';
IF arg_i ? 'm' THEN
b = Not (arg_i->>'m')::boolean;
ELSE
b = true;
END IF;
--block 3
select p.aa abc into rcd
from p
where p.pi = i
limit 1;
--block 4
IF NOT FOUND THEN
RAISE '%', msg USING ERRCODE = 'foreign_key_violation';
Return Null;
END IF;
--block 5
IF b = true and rcd.pa = false THEN
--5.1
UPDATE p set aa = true where pi = i;
--5.2
UPDATE e
SET aa = true, ab = false
WHERE aai in (select aai from aa where pi = i and zzz = false)
and dda = false;
--5.3
get diagnostics cnt = row_count;
--6
RETURN response;
--7
EXCEPTION
WHEN OTHERS THEN
GET STACKED DIAGNOSTICS stack_msg = MESSAGE_TEXT, stack = PG_EXCEPTION_CONTEXT;
RAISE WARNING '%: --- Error Stack ---:
message: %
context: %
', module, stack_msg, stack;
RAISE;
END;
$function$;
The statements can be UPDATE,EXCEPTION or plain SELECT queries based on some_id. As I understand from postgre documentation, all statements in this function are executed as a single transaction and committed at the END

syntax error at or near ";" LINE 22 - Postgresql

I am creating a user defined function in PostgreSQL and facing error.
Also, please suggest a better way (if any) to execute this function.
CREATE FUNCTION public.mark_enrollment_completed(IN enrollment_id text)
RETURNS boolean
LANGUAGE plpgsql
AS $BODY$
DECLARE
total_contents INTEGER;
completed_content_count INTEGER;
user_id TEXT;
course_id TEXT;
was_marked BOOLEAN;
BEGIN
SELECT user_id, course_id INTO user_id, course_id FROM enrollments WHERE enrollment_id = enrollment_id;
SELECT count(*) INTO total_contents FROM course_contents WHERE course_id = course_id;
SELECT count(*) INTO completed_content_count FROM completed_contents WHERE user_id = user_id;
IF total_contents = completed_content_count THEN
UPDATE enrollments SET is_completed = true WHERE enrollment_id = enrollment_id;
SET was_marked = true;
ELSE
SET was_marked = false;
RETURN was_marked;
END;
$BODY$;
Error:
ERROR: syntax error at or near ";"
LINE 22: END;
^
SQL state: 42601
Character: 750
As documented in the manual assignment is done using := operator - there is no SET in PL/pgSQL.
You are also missing the END IF
IF total_contents = completed_content_count THEN
UPDATE enrollments SET is_completed = true WHERE enrollment_id = enrollment_id;
was_marked := true;
ELSE
was_marked := false;
END IF;
RETURN was_marked;

PostgreSql procedure return query has no destination for result data

I am building a procedure, which is called by a trigger, after an insert, and an error is occurring when I use a select statement in its body.
When I do NOT use select, to get a value, there is NO error when the trigger calls this procedure:
BEGIN;
CREATE OR REPLACE FUNCTION calc_virtual()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
_virtual RECORD;
_value_calc DECIMAL;
_complet BOOLEAN;
BEGIN
_value_calc = 0
FOR _virtual IN SELECT value
FROM virtual
WHERE id = NEW.id
LOOP
_value_calc = _value_calc-(value * 1.5);
END LOOP;
INSERT INTO appointment (value) VALUES (_value_calc);
RETURN NEW;
END;
$function$;
COMMIT;
When I use select, to get a value, an error occurs when the trigger calls this procedure:
BEGIN;
CREATE OR REPLACE FUNCTION calc_virtual()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
_virtual RECORD;
_value_calc DECIMAL;
_complet BOOLEAN;
BEGIN
FOR _virtual IN SELECT value
FROM virtual
WHERE id = NEW.id
LOOP
_value_calc = 0;
_complet = TRUE;
SELECT value_active
FROM appointment_virtual
WHERE name = _virtual.name;
IF FOUND THEN
_value_calc = _value_calc-(value_active * 1.5);
ELSE
_complet = False;
END IF;
END LOOP;
IF _complet THEN
INSERT INTO appointment (value) VALUES (_value_calc);
END IF;
RETURN NEW;
END;
$function$;
COMMIT;
Thanks por any help!
You have to use SELECT ... INTO in PL/pgSQL. No variable value_active will magically be created.
SELECT value_active INTO _active
FROM appointment_virtual
WHERE name = _virtual.name;
IF FOUND THEN
_value_calc = _value_calc-(_active * 1.5);
...
You have to declare _active in the DECLARE section.

Postgres IF on variable

I'm in the process of learning postgres, I've already found a work around to this problem but I wanted to ask the community if something like this is even possible, maybe my syntax is just off.
DO $$ BEGIN
IF :MODIFYBY IS NOT NULL THEN
UPDATE User SET ModifyBy = :MODIFYBY WHERE UserId = :USERID;
UPDATE Profile SET ModifyBy = :MODIFYBY WHERE UserId = :USERID;
END IF;
END $$;
Receiving
syntax error at or near ":"
as :MODIFYBY is a parameter to this sql.
How can I test if a parameter is null?
Note: Running on PostgreSQL 9.6
Update:
It is possible my terminology is not correct. The full sql statement is this
BEGIN;
UPDATE User
SET Email = :EMAIL
,ModifyDate = now() at time zone 'utc'
WHERE
UserId = :USERID;
UPDATE Profile
SET FirstName = :FIRSTNAME
,LastName = :LASTNAME
,ModifyDate = now() at time zone 'utc'
WHERE
UserId = :USERID;
DO $$ BEGIN
IF :MODIFYBY IS NOT NULL THEN
UPDATE User SET ModifyBy = :MODIFYBY WHERE UserId = :USERID;
UPDATE Profile SET ModifyBy = :MODIFYBY WHERE UserId = :USERID;
END IF;
END $$;
COMMIT;
I added the DO $$ BEGIN and END $$; to get the IF statement to work...
I think your problem is with the use of : parameters in a function doesn't use it.
This is an example of a function using IF
CREATE OR REPLACE FUNCTION traffic.check_distance(
int_route_source_id bigint,
num_distance_geo numeric)
RETURNS boolean AS
$BODY$
DECLARE
bol_route_error boolean = false;
num_distance_rto numeric;
BEGIN
-- CALCULATE ROUTE DISTANCE
SELECT INTO num_distance_rto
....
--RAISE DISTANCE ALARM
IF num_distance_rto > 3.5 * num_distance_geo THEN
UPDATE traffic.Route_Sources
SET
IsValid = FALSE,
result = '3.5x MUY LARGO'
WHERE
route_source_id = int_route_source_id;
bol_route_error = true;
END IF;
RETURN bol_route_error;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION traffic.check_distance(bigint, numeric)
OWNER TO postgres;

Run DELETE query in trigger function

I'm trying to run a DELETE and UPDATE query inside a trigger function in PL/pgSQL.
CREATE OR REPLACE FUNCTION trg_delete_order_layer()
RETURNS trigger AS
$BODY$
DECLARE index_ INTEGER;
DECLARE a RECORD;
BEGIN
IF EXISTS (SELECT * FROM map_layers_order WHERE id_map = OLD.id_map)
THEN index_ := position FROM map_layers_order WHERE id_map = OLD.id_map AND id_layer = OLD.id_layer AND layer_type = 'layer';
ELSE index_ := 0;
END IF;
RAISE NOTICE 'max_index % % %', index_, OLD.id_map, OLD.id_layer;
EXECUTE 'DELETE FROM map_layers_order WHERE id_map = $1 AND id_layer = $2 AND layer_type = $3' USING OLD.id_map, OLD.id_layer, 'layer';
EXECUTE 'UPDATE map_layers_order SET position = position -1 WHERE id_map = $1 AND position > $2' USING OLD.id_map, index_;
VALUES (OLD.id_map, OLD.id_layer, 'layer', index_);
RETURN OLD;
END;
$BODY$
LANGUAGE plpgsql;
I don't know why i'm getting this error in the line where it runs the DELETE query:
Query has no destination for result data
Why is this error happen and how can I solve this?
Obviously if I use EXECUTE...INTO, I get a more reasonable error saying that the query has no result.