PostgreSQL Delete Trigger - postgresql

I´m creating a trigger on PGAdminIII where I want to delete the rows that have the foreign key on the other table. However I´m getting a Syntax error and I can´t find where the problem is:
CREATE TRIGGER clienteDelete
BEFORE DELETE ON cliente
FOR EACH ROW
BEGIN
DELETE FROM contacto WHERE contacto.id = OLD.contacto_idcontacto;
END;
ERROR: syntax error at or near "BEGIN"
LINE 4: BEGIN
^
********** Error **********
ERROR: syntax error at or near "BEGIN"
SQL state: 42601
Character: 68
I´m not used to the syntax of triggers on Postgres but that´s what I know according to the SQL standard. Any help will be highly apreciated

So Postgresql triggers has some limitations, for instance
PostgreSQL only allows the execution of a user-defined function for
the triggered action.
So to accomplish what you want you need to define a function and make the trigger fire that. Something like this should work:
CREATE FUNCTION clienteDelete() RETURNS TRIGGER AS $_$
BEGIN
DELETE FROM contacto WHERE contacto.id = OLD.contacto_idcontacto;
RETURN OLD;
END $_$ LANGUAGE 'plpgsql';
And the trigger:
CREATE TRIGGER delete_contacto
BEFORE DELETE ON cliente
FOR EACH ROW
EXECUTE PROCEDURE clienteDelete();
I'm no Postgresql expert though so expect the code above to not be perfect.

Related

Create procedure fails due to semicolons [duplicate]

I have the following function definition for a PostgreSQL 9.3.4 database:
CREATE OR REPLACE FUNCTION update_modified_timestamp()
RETURNS TRIGGER AS $$
BEGIN
NEW.modified_at = now();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
When I try to execute this in SQuirreL (3.5.3 or 3.6), I get the following error:
Error: ERROR: unterminated dollar-quoted string at or near "$$
BEGIN
NEW.modified_at = now()"
Position: 77
SQLState: 42601
ErrorCode: 0
So far I've learned this can be mitigated by using single quotes to delimit the function body like so:
CREATE OR REPLACE FUNCTION update_modified_timestamp()
RETURNS TRIGGER AS '
BEGIN
NEW.modified_at = now();
RETURN NEW;
END;
' LANGUAGE plpgsql;
Still I would like to know if this can't be solved otherwise - I think it must be possible since Flyway can execute this script and it uses the exact same JDBC driver that is configured in SQuirreL.
Update: #a_horse_with_no_name noted that this error has nothing to do with the JDBC driver, but with how SQuirreL parses the SQL statement and splits it into chunks before sending them to the database. Thus the remaining question is: Can SQuirreL send a query raw/unparsed? I've searched quite a bit couldn't find a way to do that.
You can change the statement separator so the statement is not split on a ;:
Go to: Session → Session Properties → SQL → Statement Separator
Even though you can't change it to an empty string, you can change it for example to //, which allows execution of the statement in the question.

PostgreSQL: skip erros in SQL clients using JDBC

I want to execute a SQL script in a client using JDBC (not the postgreSQL pslq client). In this script I would like to do something like that:
skip errors on;
alter table foo ...;
skip errors off;
Is there a way to do this with PostgreSQL >= 9.1?
I found this thread with a good solution usind DO blocks and error codes:
How to continue sql script on error?
And creating a function for my problem:
create or replace function continueOnError(v_sqlStatement text)
returns void
language plpgsql
as '
BEGIN
execute v_sqlStatement;
EXCEPTION
WHEN invalid_schema_name
OR undefined_table
OR undefined_column
THEN RAISE WARNING ''Continued on error sql statement: %'', v_sqlStatement;
END;
';
...use it:
select continueOnError('alter table test add constraint fk_test_valueid foreign key (valueid) references value(id)');

How to create a trigger in PostgreSQL without delegating control to a function?

I'm familiar with the method where the trigger is fired by a function:
CREATE TRIGGER mytrigger
BEFORE UPDATE ON mytable
FOR EACH ROW EXECUTE PROCEDURE some_function();
I would like to know if there is a way to now eliminate the need for the function. Something like this doesn't seem to work:
CREATE TRIGGER mytrigger
BEFORE UPDATE ON mytable
FOR EACH ROW
BEGIN
SET NEW.col1 = OLD.col1 + 1
END
The error I keep getting is: ERROR: syntax error at or near "BEGIN"
If I get rid of BEGIN and END, it says: ERROR: syntax error at or near "SET"
Other variations fail as well. For example:
CREATE TRIGGER mytrigger
BEFORE UPDATE ON mytable
FOR EACH ROW
UPDATE mytable SET col1 = OLD.col1 + 1;
Can this be done now? I'm currently using v9.4.
You can't do it, it simply isn't supported. That's why it isn't working.
You must use trigger functions in PostgreSQL. You can't just write some SQL in-line in the trigger.

Postgres trigger syntax

Using SQLFiddle, PostgreSQL 9.3.1.
I am learning to define triggers in PostgreSQL, and after doing some research I've found out the following:
Triggers in Postgres are different from MYSQL. Where in Postgres you must create a function that RETURNS TRIGGER, in MySQL you can just create a trigger. So this is what I've come up with:
On Employee Insert, we want to update Departments Total Salary.
CREATE FUNCTION update_sal() RETURNS TRIGGER AS $$
BEGIN
IF NEW.dno IS NOT NULL THEN
UPDATE Department SET Total_sal = total_sal + NEW.salary
WHERE department.dno = NEW.dno;
END IF;
RETURN NULL;
END;
$$ Language plpgsql;
CREATE TRIGGER updateInsert
AFTER INSERT ON Employee
FOR EACH ROW
EXECUTE PROCEDURE update_sal();
And I'm getting the following error:
Schema Creation Failed: ERROR: unterminated dollar-quoted string at or near "$$
BEGIN IF NEW.dno IS NOT NULL THEN UPDATE Department
SET Total_sal = total_sal +NEW.salary WHERE department.dno = NEW.dno":
I've solved the issue thanks to Database Function giving an error - Postgresql
It seems just changing the query terminator at the bottom of the Scheme Window solves this issue.
If you copy-pasted the code, then you've got a simple syntax error: ENDl should be END; in the last-but-one line of the function definition.
Otherwise, it looks good to me.

How do I fix this PostgreSQL 9.1 stored procedure?

We have a problem with our software and in order to correct the issue, I have to write a stored procedure that will be run as part of the upgrade process for upgrade installs. This stored procedure needs to find every row in a particular table that matches certain conditions and update that row. For internal reasons, the update has to be done through a stored procedure we wrote specifically for inserting and updating data.
Here is the stored procedure I have written to fix this issue:
CREATE OR REPLACE FUNCTION FixDataProblem() RETURNS VOID AS $$
DECLARE
FixCursor NO SCROLL CURSOR FOR
SELECT * FROM MyTable WHERE ProblemColumn IN ( '?', 'PR' );
RowToUpdate MyTable%ROWTYPE;
BEGIN
-- Open the cursor
OPEN FixCursor;
-- Start a loop
LOOP
-- Fetch the next row from thr cursor
FETCH FixCursor INTO RowToUpdate;
-- Did we get anything back?
IF RowToUpdate IS NULL THEN
-- We didn't. Exit the loop
EXIT;
END IF;
-- Call the UpsertMyTable stored procedure to set the ProblemColumn column to NULL
SELECT CarSystem.UpsertMyTable( RowToUpdate.RowId,
RowToUpdate.ForeignId,
RowToUpdate.CountryId,
NULL,
RowToUpdate.Plate,
RowToUpdate.HashedData,
RowToUpdate.PlateClassId,
RowToUpdate.AlarmClassId,
RowToUpdate.BeginDate,
RowToUpdate.EndDate,
RowToUpdate.ListPriorityId,
RowToUpdate.VehicleTypeId,
RowToUpdate.MakeId,
RowToUpdate.ModelId,
RowToUpdate.Year,
RowToUpdate.ColorId,
RowToUpdate.Notes,
RowToUpdate.OfficerNotes,
NULL,
UUID_GENERATE_V4() );
END LOOP;
-- Close the cursor
CLOSE ListDetailsCursor;
END;
$$ LANGUAGE plpgsql;
This stored procedure fine, but when I run it, I get:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function "fixdataproblem" line 22 at SQL statement
********** Error **********
ERROR: query has no destination for result data
SQL state: 42601
Hint: If you want to discard the results of a SELECT, use PERFORM instead.
Context: PL/pgSQL function "fixdataproblem" line 22 at SQL statement
How do I fix this issue? I believe I am calling the stored procedure correctly. I really don't know what the issue with this stored procedure is.
Thanks
Tony
It says right there:
ERROR: query has no destination for result data
HINT: If you want to discard the results of a SELECT, use PERFORM instead.
CONTEXT: PL/pgSQL function "fixdataproblem" line 22 at SQL statement
And on line 22:
-- Call the UpsertMyTable stored procedure to set the ProblemColumn column to NULL
SELECT CarSystem.UpsertMyTable( RowToUpdate.RowId,
...
Change it from SELECT to PERFORM. See PERFORM for why.