Postgres trigger syntax - postgresql

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.

Related

postgresql CONCAT function error when use in a trigger

This might be a stupid question but pardon me, I'm trying to convert one of my MariaDB database into a PostgreSQL database. Here I'm getting an error while executing this function.
I cannot find what's wrong here,
create function tg_prodcut_insert()
returns trigger as '
BEGIN
SET NEW.id = CONCAT(1, LPAD(INSERT INTO product_seq VALUES (NULL) returning id, 6, 0));
END;
' LANGUAGE 'plpgsql';
Error is pointing to the 1 in CONCAT method, The type of id I'm trying to SET is char(7)
EDIT
I also tried this, this won't work either,
create function tg_orders_insert()
returns trigger as '
BEGIN
INSERT INTO order_seq VALUES (NULL);
SET NEW.id = CONCAT('1', LPAD(LAST_INSERT_ID(), 6, 0));
END;
' LANGUAGE 'plpgsql';
Thanks in advance.
It seems you are trying to simulate some kind of sequence with that code by inserting into a table and then getting the auto_increment value from that.
This can be done much more efficiently using a sequence in Postgres.
The error you get also isn't caused by the concat() function but because you are using the wrong syntax.
Value assignment is done using := in PL/pgSQL.
And there is also no last_insert_id() function in Postgres. To get the next value from a sequence use nextval(), to get the most recently generated value, you can use lastval() but that's not necessary here.
create sequence product_id_seq;
create function tg_product_insert()
returns trigger as
$$
BEGIN
NEW.id := concat('ORD', to_char(nextval('product_id_seq'), 'FM00000000'));
return new;
END;
$$
LANGUAGE plpgsql;
you will need to create a before trigger for that to work:
create trigger product_seq_trigger
before insert on product
for each row
execute procedure tg_product_insert();
Online example
But it would be a lot more efficient to switch to a proper identity column instead and get rid of the trigger.

Not able to dynamically truncate table in Redshift Stored Procedure

I have a table in Redshift (let's call it a status table) where I set the status of tables which I want to truncate. I created a Redshift Stored Procedure in order to achieve that. Here is my code for the SP:
CREATE OR REPLACE PROCEDURE <schema>.truncate_table()
AS $$
DECLARE
v_tpsl RECORD;
exec_statement VARCHAR(256);
BEGIN
FOR v_tpsl in SELECT * from <schama>.tablename_process_status_log WHERE status = 'TRUE' LOOP
exec_statement = 'TRUNCATE TABLE <schema>.' + quote_ident(v_tpsl.staging_table_name) + '_test;';
RAISE INFO 'statement = %', exec_statement;
EXECUTE exec_statement;
END LOOP;
END;
$$
LANGUAGE plpgsql;
Now when I am CALLING the Stored Procedure, I am getting this error:
SQL Error [500310] [34000]: [Amazon](500310) Invalid operation: cursor does not exist;
I looked at the documentation of the SP to check if Truncate is possible or not. By looking at the examples, it looks like it's possible.
I am not sure what is going wrong in this. I am using RedshiftJDBC42-no-awssdk-1.2.34.1058.jar and connecting via DBeaver.
It looks like I have found the answer. According to this, Any cursor that is open (explicitly or implicitly) is closed automatically when a COMMIT, ROLLBACK, or TRUNCATE statement is processed. In my next iteration of the loop, it's trying to accessing the cursor which is already closed.

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 Delete Trigger

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.

Yet another stored procedure syntax error - IF-THEN-ELSE

Using postgresql 8.4, I'm trying to write a function, and it looks like this:
CREATE OR REPLACE FUNCTION addorupdate( smallint, varchar(7) ) RETURNS void AS
$$
BEGIN
IF EXISTS (SELECT * FROM consist WHERE slave = $1) THEN
UPDATE consist SET
master = $2
where slave = $1;
ELSE
INSERT INTO consist(slave, master) VALUES ( $2, $1 );
END IF;
END;
$$
LANGUAGE SQL;
However, it fails like this:
ERROR: syntax error at or near "IF"
LINE 4: IF EXISTS (SELECT * FROM consist WHERE slave = $1) THEN
...and I've been wasting too much time and caffeine on figuring out why and could use someone with fresh eyes to help me out.
If it's not clear what i'm trying to achieve:
slaves is a column of unique values. If it exists, UPDATE it with the current master. If not, INSERT.
UPDATE:
Changed language to plpgsql, and it now throws:
ERROR: language "plpgsql" does not exist
UPDATE:
CREATE LANGUAGE plpgsql;
(: RESOLVED :)
Your language needs to be plpgsql not sql.