syntax error at or near ";" LINE 22 - Postgresql - 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;

Related

I tried to execute a query and gave me an error and i can't understand why?

DROP FUNCTION IF EXISTS top_5(customers.customerid%TYPE, products.prod_id%TYPE, orderlines.quantity%TYPE) CASCADE;
CREATE OR REPLACE FUNCTION top_5(c_id customers.customerid%TYPE, p_id products.prod_id%TYPE, quant orderlines.quantity%TYPE)
RETURNS orders.orderid%TYPE AS $$
DECLARE
top_prod CURSOR IS
SELECT inv.prod_id
FROM inventory AS inv, products AS prod
WHERE inv.prod_id=prod.prod_id
ORDER BY inv.quan_in_stock desc, inv.sales
limit 5;
ord_id orders.orderid%TYPE;
ord_date orders.orderdate%TYPE:= current_date;
ordln_id orderlines.orderlineid%TYPE:=1;
BEGIN
SELECT nova_orderid() INTO ord_id;
INSERT INTO orders(orderid, orderdate,customerid,netamount,tax,totalamount) VALUES(ord_id,ord_date,c_id,0,0,0);
PERFORM compra(c_id, p_id, 1::smallint, ord_id, ordln_id, ord_date);
IF (p_id = top_prod) THEN
UPDATE orders
SET totalamount = totalamount - (totalamount*0.2)
WHERE ord_id = (SELECT MAX(ord_id) FROM orders);
END IF;
END;
$$ LANGUAGE plpgsql;
I have the following code and when i try to execute this
SELECT top_5(1,1,'2');
i have this error
ERROR: operator does not exist: integer = refcursor
LINE 1: SELECT (p_id = top_prod)
You need to get the 'prod_id' value from the cursor 'top_prod'.
You cannot compare two types.
Try this,
DECLARE
top_prod_id top_prod%ROWTYPE;
BEGIN
OPEN top_prod;
LOOP
FETCH top_prod INTO top_prod_id;
EXIT WHEN top_prod %NOTFOUND;
IF (p_id = top_prod_id) THEN
UPDATE orders
SET totalamount = totalamount - (totalamount*0.2)
WHERE ord_id = (SELECT MAX(ord_id) FROM orders);
END IF;
END LOOP;
CLOSE top_prod;
END;

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;

Postgresql dynamic sql syntax error

I have a function that accepts an array of table names and loops through the array to create a trigger for each table. The function compiles and is created with no errors.
When I go try to run the function I keep getting the following error and I am not sure what's wrong with my syntax
ERROR:
ERROR: unterminated quoted string at or near "';
ELSE
RAISE EXCEPTION ''[audit.if_modified_func] - Trigger func added as trigger for unhandled case: %, %'',TG_OP, TG_LEVEL;
RETURN NULL;
END IF;
INSERT INTO audit.Organization VALUES (audit_row.*);
RETURN null;
END;
"
LINE 53: audit_row.statement_only = 't';
^
USAGE:
SELECT audit.temp_create_trigger(ARRAY['Organization'])
Here's the function:
CREATE OR REPLACE FUNCTION audit.temp_create_trigger(table_names character varying[])
RETURNS character varying AS
$BODY$
DECLARE
table_name varchar;
i int;
BEGIN
FOR i in 1..array_upper(table_names, 1) LOOP
EXECUTE format('CREATE OR REPLACE FUNCTION audit.trigger_function_%1$s() RETURNS TRIGGER AS $$
DECLARE
audit_row audit.%1$s;
include_values boolean;
log_diffs boolean;
h_old hstore;
h_new hstore;
excluded_cols text[] = ARRAY[]::text[];
BEGIN
IF TG_WHEN <> ''AFTER'' THEN
RAISE EXCEPTION ''audit.trigger_function_%1$s may only run as an AFTER trigger'';
END IF;
audit_row = ROW(
nextval(''audit.%1$s_event_id_seq''), -- event_id
TG_TABLE_SCHEMA::text, -- schema_name
TG_TABLE_NAME::text, -- table_name
TG_RELID, -- relation OID for much quicker searches
session_user::text, -- session_user_name
current_timestamp, -- action_tstamp_tx
statement_timestamp(), -- action_tstamp_stm
clock_timestamp(), -- action_tstamp_clk
txid_current(), -- transaction ID
current_setting(''application_name''), -- client application
inet_client_addr(), -- client_addr
inet_client_port(), -- client_port
current_query(), -- top-level query or queries (if multistatement) from client
substring(TG_OP,1,1), -- action
NULL, NULL, -- row_data, changed_fields
''f'' -- statement_only
);
IF NOT TG_ARGV[0]::boolean IS DISTINCT FROM ''f''::boolean THEN
audit_row.client_query = NULL;
END IF;
IF TG_ARGV[1] IS NOT NULL THEN
excluded_cols = TG_ARGV[1]::text[];
END IF;
IF (TG_OP = ''UPDATE'' AND TG_LEVEL = ''ROW'') THEN
audit_row.row_data = hstore(OLD.*) - excluded_cols;
audit_row.changed_fields = (hstore(NEW.*) - audit_row.row_data) - excluded_cols;
IF audit_row.changed_fields = hstore('') THEN
-- All changed fields are ignored. Skip this update.
RETURN NULL;
END IF;
ELSIF (TG_OP = ''DELETE'' AND TG_LEVEL = ''ROW'') THEN
audit_row.row_data = hstore(OLD.*) - excluded_cols;
ELSIF (TG_OP = ''INSERT'' AND TG_LEVEL = ''ROW'') THEN
audit_row.row_data = hstore(NEW.*) - excluded_cols;
ELSIF (TG_LEVEL = ''STATEMENT'' AND TG_OP IN (''INSERT'',''UPDATE'',''DELETE'',''TRUNCATE'')) THEN
audit_row.statement_only = ''t'';
ELSE
RAISE EXCEPTION ''''[audit.if_modified_func] - Trigger func added as trigger for unhandled case: %%, %%'''',TG_OP, TG_LEVEL;
RETURN NULL;
END IF;
INSERT INTO audit.%1$s VALUES (audit_row.*);
RETURN null;
END;
$$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION audit.trigger_function_%1$s()
OWNER TO postgres;', table_names[i]);
EXECUTE format('CREATE TRIGGER audit.%1$s_trigg
BEFORE INSERT OR UPDATE
ON audit.%1$s
FOR EACH ROW
EXECUTE PROCEDURE audit.trigger_function_%1$s();', table_names[i]);
END LOOP;
RETURN 'SUCCESS';
END;
$BODY$
LANGUAGE plpgsql
COST 100;
ALTER FUNCTION audit.temp_create_trigger(character varying[])
OWNER TO postgres;
There are missing and superfluous quotes :
--IF audit_row.changed_fields = hstore('') THEN -- missing quotes
IF audit_row.changed_fields = hstore('''') THEN
.....
--RAISE EXCEPTION ''''[audit.if_modified_func] - Trigger func added as trigger for unhandled case: %%, %%'''',TG_OP, TG_LEVEL; --more quotes then needed
RAISE EXCEPTION ''[audit.if_modified_func] - Trigger func added as trigger for unhandled case: %%, %%'',TG_OP, TG_LEVEL;

PGSQL error for If statement in function

I'm trying to create a function for pgsql where I need to return a boolean if an equipment exists in a lecture hall. I'm getting the following error:
"ERROR: return type mismatch in function declared to return boolean"
"DETAIL: Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING."
CREATE FUNCTION hasProjector(int) RETURNS boolean AS $$
DO
$do$
BEGIN
IF EXISTS(SELECT * FROM LectureRoomEquipment WHERE LectureRoomID = $1 AND EquipmentID = 1) THEN
SELECT true AS hasProjector;
ELSE
SELECT false AS hasProjector;
END IF;
END
$do$
$$ LANGUAGE SQL;
Does anyone advise me what i'm doing wrong and how I can fix this? Thank you.
You don't need plpgsql. Do it as plain SQL
create function hasprojector(int) returns boolean as $$
select exists (
select *
from lectureroomequipment
where lectureroomid = $1 and equipmentid = 1
);
$$ language sql;

"Function does not exist" error when creating the function with more parameters

I have dropped a PL/pgSQL function and I try to recreate it with one more parameter (with default value). But I get a strange error:
ERROR: function vytvor_kod_sj(text, integer, integer) does not exist
SQL state: 42883
I would expect such an error while dropping or calling the function, not while creating it. I made sure that the error occurs exactly while trying to create it, not in any of the other functions or triggers I created from the same sql file.
I made a dummy function without the last parameter and it works now, but it is definitely not what I want - not only I don't need the function without the last parameter anymore, I usually call the function only with the first two or three parameter, so I need to drop it just after creating the new version of my function to avoid mismatches. Fortunately, there are no errors while doing this, but it is hardly optimal solution.
So does anyone know how to solve this mysterious problem?
I have PostgreSQL 9.3.4 on Windows 32; I use pgAdmin 1.18.1
My code:
CREATE OR REPLACE FUNCTION vytvor_kod_sj( _akce text, typ_sj integer,
podtyp integer DEFAULT 0, styl integer DEFAULT NULL )
RETURNS text AS $$
DECLARE
--styl integer;
_nazev_seq text;
_min integer;
_max integer;
_nazev text;
_soucasna integer;
BEGIN
IF styl IS NULL THEN
SELECT nomenklatura INTO styl FROM akce WHERE kod_akce = _akce;
END IF;
IF NOT EXISTS( SELECT id_nom FROM pro_nom_pravidlo_sj
WHERE id_nom = styl AND sj = typ_sj AND typ = podtyp ) THEN
IF podtyp = 0 OR NOT EXISTS( SELECT id_nom FROM pro_nom_pravidlo_sj
WHERE id_nom = styl AND sj = typ_sj AND typ = 0 ) THEN
RAISE NOTICE 'Pro daný typ stratigrafické jednotky není vytvořeno žádné pravidlo!';
RETURN NULL;
ELSE
podtyp := 0;
END IF;
END IF;
_nazev_seq := _akce || '_' || typ_sj || '_' || podtyp || '_seq';
IF NOT EXISTS (SELECT 0 FROM pg_class where relname = _nazev_seq ) THEN
SELECT min, max INTO _min, _max FROM pro_nom_pravidlo_sj
WHERE id_nom = styl AND sj = typ_sj AND typ = podtyp;
IF _max IS NOT NULL THEN
EXECUTE format('CREATE SEQUENCE %I MINVALUE %s MAXVALUE %s ', _nazev_seq, _min, _max);
ELSE
EXECUTE format('CREATE SEQUENCE %I MINVALUE %s ', _nazev_seq, _min);
END IF;
END IF;
--IF strict IS TRUE THEN
RETURN (
SELECT predpona FROM pro_nom_pravidlo_sj
WHERE id_nom = styl AND sj = typ_sj AND typ = podtyp
) || CAST(nextval(_nazev_seq) AS TEXT);
--END IF;
END;
$$ LANGUAGE plpgsql
SECURITY DEFINER;
ALTER FUNCTION vytvor_kod_sj( text, integer, integer ) OWNER TO ins_daemon;
The old version had styl variable declared, not as a parameter, and there was no test whether it is null. Otherwise I didn't change anything.
I noticed the cause of the problem just after posting the question:
ALTER FUNCTION vytvor_kod_sj( text, integer, integer ) OWNER TO ins_daemon;
It tries to alter the old function.