I'm trying to do a trigger that will verify if a record exists in the table passed as argument. I'm doing it as a laravel migration but nervertheless the SQL should be perceptible
DB::unprepared('
CREATE OR REPLACE FUNCTION insert_or_update_lojas() RETURNS trigger AS $insert_or_update_lojas$
DECLARE
store TEXT := TG_ARGV[0]::TEXT;
BEGIN
-- Check if product exists
IF
EXISTS (SELECT 1 FROM TG_ARGV[0]::TEXT WHERE ean = NEW.ean)
THEN
UPDATE store SET price_form_factor=NEW.price_form_factor, price_unit=NEW.price_unit WHERE ean=NEW.ean;
RETURN NULL;
END IF;
RETURN NEW;
END;
$insert_or_update_lojas$ LANGUAGE plpgsql;');
DB::unprepared('
CREATE TRIGGER insert_or_update_continente BEFORE INSERT ON continente FOR EACH ROW EXECUTE PROCEDURE insert_or_update_lojas(\'continente\');');
Right now I'm getting
relation "store" does not exist LINE 1: SELECT EXISTS (SELECT 1 FROM store WHERE ean = NEW.ean) ^ QUERY: SELECT EXISTS (SELECT 1 FROM store WHERE ean = NEW.ean) CONTEXT: PL/pgSQL function insert_or_update_lojas() line 6 at IF
EDIT:
After googling for the past day i slightly changed the if statement. IF EXECUTE format(\'EXISTS SELECT 1 FROM %s WHERE ean = NEW.ean\', store) THEN EXECUTE (\'UPDATE store SET price_form_factor=NEW.price_form_factor, price_unit=NEW.price_unit WHERE ean=NEW.ean\'); RETURN NULL; END IF;
I know the format() works. However when I do EXECUTE format() I get the following error:
SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "("
LINE 8:
EXECUTE format('EXISTS SELECT 1 FROM %s WHER...
^
(SQL:
CREATE OR REPLACE FUNCTION insert_or_update_lojas() RETURNS trigger AS $insert_or_update_lojas$
DECLARE
store TEXT := quote_ident(TG_ARGV[0]);
BEGIN
-- Check if product exists
IF
EXECUTE format('EXISTS SELECT 1 FROM %s WHERE ean = NEW.ean', store)
THEN
EXECUTE ('UPDATE store SET price_form_factor=NEW.price_form_factor, price_unit=NEW.price_unit WHERE ean=NEW.ean');
RETURN NULL;
END IF;
Related
This question already has answers here:
syntax Error in PostgreSQL when I try to create Trigger
(2 answers)
Closed last year.
I am getting a syntax error for my code which I can't understand why
am I missing something?
also, I read this I did not get my answer
syntax Error in PostgreSQL when I try to create Trigger
CREATE TRIGGER MyExampleName AFTER INSERT ON baskets
FOR EACH ROW BEGIN
UPDATE customers
SET customers.credit=customers.credit - NEW.amount
WHERE customers.id = NEW.customer_id;
END;
and tried it like this as well:
CREATE TRIGGER MyExampleName AFTER INSERT ON baskets
FOR EACH ROW AS $$ BEGIN
UPDATE customers
SET customers.credit=customers.credit - NEW.amount
WHERE customers.id = NEW.customer_id;
END;
$$ LANGUAGE plpgsql;
Error:
ERROR: syntax error at or near "BEGIN"
LINE 2: FOR EACH ROW BEGIN
^
SQL state: 42601
Character: 67
I'd say the first comment on your question pretty much covers it all. You cannot put the trigger code in the trigger body, you must first create a separate function and include the function call inside the trigger body.
This example comes directly from the Postgres docs:
-- 1. Create the function that does what you need
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname cannot be null';
END IF;
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% cannot have null salary', NEW.empname;
END IF;
-- Who works for us when they must pay for it?
IF NEW.salary < 0 THEN
RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
END IF;
-- Remember who changed the payroll when
NEW.last_date := current_timestamp;
NEW.last_user := current_user;
RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;
-- 2. Create the trigger with the 'EXECUTE FUNCTION function_name' part
-- replacing the actual function name from step 1.
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW EXECUTE FUNCTION emp_stamp();
I have a stored procedure which I'm trying to use to delete several rows of a table based on an array of id's, from the rows that are deleted I want to return those id's and store them in a variable so that it can be used in another delete statement. Here's a reduced segment of my function.
create or replace function "table_a"."deletes"
(p_ids int[]
)
returns int
as $$
declare
v_directories int[];
begin
delete from "table_a"."foo" where "hoo_id" = any(unnest(p_ids)) returning id into v_dirs;
delete from "table_a"."bar" where "foo_id" = any(unnest(v_dirs));
return 1;
exception
when others
then raise exception '% %', sqlstate, sqlerrm;
end;
$$ LANGUAGE plpgsql;
This gives me an error of -
'set-returning functions are not allowed in WHERE'
What am I missing?
Use a CTE instead:
with ids as (
delete from "table_a"."foo"
where "hoo_id" = any(unnest(p_ids))
returning id
)
delete from "table_a"."bar"
where "foo_id" in (select id from ids);
I need to create plpgsql methods which use current row value without passing in parameter in update command.
I tried
create temp table test ( test text, result text ) on commit drop;
insert into test values ('1','');
CREATE OR REPLACE FUNCTION public.gettest() RETURNS text AS $$
DECLARE
comp text := NULL;
BEGIN
EXECUTE 'SELECT ''Current row is '' ||test.test' INTO comp;
RETURN comp;
END; $$ LANGUAGE plpgsql STRICT STABLE;
update test set result = 'Result: ' || gettest();
but got exception
ERROR: missing FROM-clause entry for table "test"
LINE 1: SELECT 'Current row is ' ||test.test
^
QUERY: SELECT 'Current row is ' ||test.test
CONTEXT: PL/pgSQL function gettest() line 6 at EXECUTE statement
********** Error **********
ERROR: missing FROM-clause entry for table "test"
SQL state: 42P01
Context: PL/pgSQL function gettest() line 6 at EXECUTE statement
How to fix ?
How to fix without passing vaue to plpgsql method parameter ?
There is no such thing as an "implicit current row". You have to pass the the function whatever it needs as a parameter. You can however pass a complete row if you want to:
create temp table test (val text, result text ) on commit drop;
insert into test values ('1','');
insert into test values ('2','');
CREATE OR REPLACE FUNCTION gettest(p_test test) RETURNS text AS $$
DECLARE
comp text := NULL;
BEGIN
comp := 'Current row is '||p_test.val;
RETURN comp;
END; $$ LANGUAGE plpgsql STRICT STABLE;
update test set result = 'Result: ' || gettest(test);
I had to rename the column test to something else, otherwise the call gettest(test) would refer to the column not the whole table (=row) and thus it didn't work.
1) Create a procedure (PrintProc) that prints out "This is the Final Test".
2) Create a procedure (UpdateProc) that takes a 'student Id' and then updates his State to ‘New York’.
Pic student database
Pic of faculty database
For #1 is it
CREATE OR REPLACE
PROCEDURE PrintProc IS
BEGIN
DBMS_OUTPUT.PUT_LINE(’This is the Final Test’);
END;
To execute I did
begin
PrintProc;
end;
but I got an error
For #2 is it
CREATE OR REPLACE PROCEDURE UpdateProc
AS
BEGIN
Update Student
set s_state = 'New York'
where s_state = 'WI'
END;
and got this error Error at line 6: PL/SQL: ORA-00933: SQL command not properly ended
to execute it is it
Begin
UpdateProc;
end;
6) Create a procedure (PrintStudentsProc) that prints out a list of students who have been taught by Kim Cox.
CREATE OR REPLACE PROCEDURE PrintStudentsProc
AS
BEGIN
Select S.S_ID, F.F_ID
FROM Faculty F INNER JOIN STUDENT S ON F.F_ID = S.F_ID
WHERE F.F_ID = 1
END;
and I get this error Error at line 4: PLS-00428: an INTO clause is expected in this SELECT statement
Was about to make another topic about triggers but stackoverflow bugged out again and I can't post for -9 days cause I posted 6 recent(not even recent) questions.
5) Create a trigger (UpdateTrigger) that outputs a message saying "Student record is going to be updated” Before the Update Takes place on Student Table,
I did
CREATE OR REPLACE TRIGGER UpdateTriggers
BEFORE UPDATE ON StudentsInfo
BEGIN
DBMS_OUTPUT.PUT_LINE('Student record is going to be updated');
Update StudentsInfo Set StudentsUpdated = StudentsUpdated + 1;
End;
and how would I execute it?
begin
UpdateTriggers;
end;
1. Error in PrintProc
The error in following code:
begin
PrintProc;
end;
is caused by the invalid character ’ in DBMS_OUTPUT.PUT_LINE in PrintProc. Replace ’ with ', this should resolve that error.
DBMS_OUTPUT.PUT_LINE('This is the Final Test');
2. Error in UpdateProc
The error in UpdateProc is caused by missing semi-colon in update statement. Add semicolon like the following:
Update Student
set s_state = 'New York'
where s_state = 'WI';
3. Error in PrintStudentsProc
Regarding the error in PrintStudentsProc, you can't do plain select statement inside plsql block. You need to use cursor. Also, you are missing semi-colon in the following query:
Select S.S_ID, F.F_ID
FROM Faculty F INNER JOIN STUDENT S ON F.F_ID = S.F_ID
WHERE F.F_ID = 1;
Cursor for loop example:
CREATE OR REPLACE PROCEDURE PrintStudentsProc AS
BEGIN
FOR stud_rec IN (
Select S.S_ID SID, F.F_ID FID
FROM Faculty F INNER JOIN STUDENT S ON F.F_ID = S.F_ID
WHERE F.F_ID = 1)
LOOP
DBMS_OUTPUT.PUT_LINE(stud_rec.SID||', '||stud_rec.FID);
END LOOP;
END;
/
Have a look at other types of cursors here
4. Error in Trigger
For trigger, after creating the trigger you need to execute the statement which invokes the trigger. In your case it is before update, so you need to perform a update query on the table.
CREATE OR REPLACE TRIGGER update_trigger BEFORE
update ON StudentsInfo FOR EACH ROW
DECLARE
stud_updated int;
BEGIN
DBMS_OUTPUT.PUT_LINE('Student record is going to be updated');
select StudentsUpdated into stud_updated from StudentsInfo where s_id=:new.s_sid;
--increase the value
stud_updated := stud_updated+1;
Update StudentsInfo Set StudentsUpdated = :stud_updated;
DBMS_OUTPUT.PUT_LINE('Student updated count:'||stud_updated);
END;
/
The above trigger should be able to execute, whenever you perform an update on the StudentsInfo table.
Also, check this sqlfiddle
I have a stored procedure that updates records if they exist, or adds a new record if they don't exist.
SQL:
CREATE OR REPLACE PROCEDURE ADDRECORD(ihost VARCHAR, iip VARCHAR)
AS
rc VARCHAR(4000);
ROWCOUNT NUMBER;
BEGIN
rc := 'select count(0) from myTable where physical_host = ihost and primary_ip = iip';
ROWCOUNT := to_number(rc, '99');
IF ROWCOUNT = 1 THEN
UPSERTRECORD(ihost, iip);
ELSE
INSERT INTO myTable(PHYSICAL_HOST, PRIMARY_IP)
VALUES (ihost, iip);
INSERT INTO IP (IP, IP_IND) VALUES (iip, 'V');
END IF;
END ADDRECORD;
The UPSERTRECORD is another stored procedure that is being called. It works fine. In fact, the error is occurring on the line that contains the to_number. The error is :
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
Is there another way to do this? Sorry, I'm not super experienced with SQL, but I need to get this figured out.
Do
DECLARE rowcount As Number(38)
select count(*) INTO rowcount from myTable
where physical_host = ihost and primary_ip = iip