I am trying to get this mysql trigger to work in mysql workbench. It will happily tell me when there is an error, but the minute everything appears ok it doesn't run. I've run a show triggers query and nothing is returned. Running v8.0.28.
delimiter //
CREATE TRIGGER add_job_item
AFTER INSERT ON estimate_line
FOR EACH ROW
BEGIN
IF (NEW.CoreTypeID = 3 AND NEW.CoreResourceID IS NOT NULL) THEN BEGIN
INSERT INTO job_items (EstimateLineID) VALUES (NEW.EstimateLineID);
END; # END IF; here doesn't work
END;// # I have tried END; END;//
delimiter ;
Oddly (and I've left it here) the ;// is actually given as an example on the Mysql documentation but errors when I run it (https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html).
I tested this on MySQL 8.0.31 and it works:
delimiter //
CREATE TRIGGER add_job_item
AFTER INSERT ON estimate_line
FOR EACH ROW
BEGIN
IF (NEW.CoreTypeID = 3 AND NEW.CoreResourceID IS NOT NULL) THEN
INSERT INTO job_items (EstimateLineID) VALUES (NEW.EstimateLineID);
END IF;
END//
delimiter ;
Differences:
IF must be ended by END IF;.
You don't need a BEGIN...END within an IF block (unless you need to use DECLARE in the block). It's already a compound statement, and accepts a list of statements in the block.
You do need to use the current delimiter after the last END. That is, END// in this example.
Related
I'm not receiving an error currently when running the query to create a trigger but after running it I can't execute another query. It is as if I haven't closed some encapsulation:
DELIMITER // CREATE TRIGGER trigger_name BEFORE DELETE ON existingtable for each row begin INSERT INTO new_delete_table (column) values(old.column) end; END DELIMITER;
I am using command line and start with:
mysql>
I execute and receive a new:
mysql>
which is the normal behavior when a query is successful. If I then try to see my triggers I end up in an infinite loop where it is waiting for me to enter some character to close something.
mysql> show triggers;
->
I can use ctrl + c to exit the function but that boots me out of MySQL as well. When I log back in my trigger is not present and I can't find any errors.
The DELIMITER command is special. All characters following the command until the end of line are interpreted as a string that you want to use as the new delimiter.
You must not put code on the same line, because all of that code will become part of the new delimiter. This is why you got no error, but no CREATE TRIGGER statement was executed. It only became part of a very long delimiter string.
The reason that DELIMITER must interpret the end-of-line as the end of the command is that it doesn't accept ; as the end of the DELIMITER command. If it did, there would be no way to reset the delimiter back to ;.
You asked in a comment if you need newlines. Aside from the newlines after DELIMITER commands, you do not need newlines. You can do this:
DELIMITER //
CREATE TRIGGER trigger_name BEFORE DELETE ON existingtable FOR EACH ROW BEGIN INSERT INTO new_delete_table (column) VALUES(old.column) END //
DELIMITER ;
(Remember to use // as the delimiter at the end of the CREATE TRIGGER statement.)
Youhave some errors in your code
every code line must end in a semicolon and you have an END to much
DELIMITER //
CREATE TRIGGER trigger_name BEFORE DELETE ON existingtable
for each row
begin
INSERT INTO new_delete_table (`column`) values
(old.column) ;
end//
DELIMITER;
I am getting this error on the SQL schema. The error message i am getting is
"
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'CREATE TRIGGER updtrigger_r4_balance AFTER UPDATE ON
resellers4 FOR EACH R' at line 2"
What syntax is going wrong? I am attaching 2 SQL schema. Both having same problem.
delimiter // DROP TRIGGER IF EXISTS updtrigger_r4_balance;
CREATE TRIGGER updtrigger_r4_balance AFTER
UPDATE
ON resellers4 FOR EACH ROW
BEGIN
IF NEW.callsLimit <= 0
THEN
UPDATE
resellers4_child r4c
INNER JOIN
resellers3 r3
ON (r4c.reseller3_id = r3.id)
SET
r4c.reseller3_callsLimit = r4c.reseller3_callsLimit + r3.callsLimit, r3.callsLimit = 0
WHERE
r4c.reseller4_id = new.id;
END
IF;
END
// delimiter ;
Another one is:
delimiter //
DROP TRIGGER
IF EXISTS updtrigger_r4_balance_add;
CREATE TRIGGER updtrigger_r4_balance_add BEFORE UPDATE ON resellers4 FOR EACH ROW
BEGIN
IF OLD.callsLimit <= 0 THEN
UPDATE resellers3 r3
INNER JOIN resellers4_child r4c ON (r4c.reseller3_id=r3.id)
SET
r3.callsLimit = r3.callsLimit+r4c.reseller3_callsLimit,
r4c.reseller3_callsLimit = 0
WHERE r4c.reseller4_id=new.id;
END IF;
END
//
delimiter ;
After you change the delimiter you have to use it instead of ;
delimiter //
DROP TRIGGER IF EXISTS updtrigger_r4_balance_add; <--- use // instead
MySQL uses ; to separate the queries. Multiple queries can be sent to the server in a single request; the server use the current delimiter (default ;) to split the received text into queries.
There are complex SQL constructs (triggers, stored procedures etc) that may include one or more queries or a BEGIN..END compound statement in their definition.
Because such constructs usually contains two or more queries, separated by the usual delimiter (;), MySQL needs a way to know where the enclosing compound construct ends.
The DELIMITER statement is used to replace the default delimiter (;) with a different one when a compound statement is defined. This allows the standard delimiter (;) to be used inside the body of the compound statement.
It works this way:
The DELIMITER statement is used to change the current delimiter; various values are used as delimiter instead. // is suggested in the documentation but other values can be used too. The only rule is to use a character (or a sequence of characters) that does not appear in the compound statement that is to be defined after it.
From now on, all the subsequent queries must end with the new delimiter (and not with ;).
Declare the complex construct (be it a trigger, stored procedure at event). If it contains more than one statements they have to be separated by ;.
End the complex construct with the delimiter declared on step 1.
Use DELIMITER ; to reset the delimiter. If another statement follows then you have to terminate the DELIMITER statement with the delimiter you set on step 1 (because it is the current delimiter; the new one becomes effective after this statement is parsed and executed).
The solution of your problem is simple: either you use the delimiter you set (//) to separate the DROP TRIGGER and the CREATE TRIGGER statements:
delimiter //
DROP TRIGGER
IF EXISTS updtrigger_r4_balance_add //
CREATE TRIGGER updtrigger_r4_balance_add BEFORE UPDATE ON resellers4 FOR EACH ROW
BEGIN
...
END
//
delimiter ;
Or you move the DROP TRIGGER statement before the DELIMITER statement and leave it as it is (terminated with ;):
DROP TRIGGER
IF EXISTS updtrigger_r4_balance_add;
delimiter //
CREATE TRIGGER updtrigger_r4_balance_add BEFORE UPDATE ON resellers4 FOR EACH ROW
BEGIN
...
END
//
delimiter ;
Also after delimiter changes try to replace word new in statement
r4c.reseller4_id = new.id;
with uppercase one. Because OLD and NEW are MySQL extensions to triggers, so they aren't case sensitive.
I am writing a stored procedure on MYSQL to check if there are recording matching some criteria and output values.
I am used to write in MSSQLSEVER
here is an excerpt of the procedure:
CREATE PROCEDURE prc1(
IN input VARCHAR(15),
OUT output INT
)
this_proc:
BEGIN
SET output = 0;
DECLARE inputCount INT DEFAULT 0;
SELECT COUNT(name) INTO inputCount FROM table WHERE table.name = input;
IF (inputCount> 0) THEN
SET output= 1;
LEAVE this_proc;
END IF;
END;
i am getting errors at each one of this lines:
SET output = 0;
DECLARE ...
IF ...
END IF;
END;
am i doing any syntax error or something?
Give this a shot. It gets past syntax errors, cleans up labels, points you toward fixing mytablename, wraps with delimiters, shows call.
drop procedure if exists prc1;
DELIMITER $$
CREATE PROCEDURE prc1(
IN input VARCHAR(15),
OUT output INT
)
-- this_proc:
BEGIN
DECLARE inputCount INT;
set input=0;
SET output = 0;
SELECT COUNT(name) INTO inputCount FROM mytablename WHERE name = input; -- fix mytablename
IF (inputCount> 0) THEN
SET output= 1;
-- LEAVE this_proc; -- not necessary, you are about to leave anyway !
END IF;
END;
$$ -- signify end of block
DELIMITER ; -- reset to default delimiter
Test it
call prc1('fred',#myVar);
Delimiters
Delimiters are important to wrap the block of the stored proc creation. The reason is so that mysql understands that the sequence of statements that follow are still part of the stored proc until it reaches the specified delimiter. In the case above, I made up one called $$ that is different from the default delimiter of a semi-colon that we are all used to. This way, when a semi-colon is encountered inside the stored proc during creation, the db engine will just consider it as one the many statements inside of it instead of terminating the stored proc creation. Without doing this delimiter wrapping, one can waste hours trying to create their first stored proc getting Error 1064 Syntax errors. At the end of the create block I merely have a line
$$
which tell mysql that that is the end of my creation block, and then the default delimiter of a semi-colon is set back with the call to
DELIMITER ;
Mysql manual page Using Delimiters with MySqlScript. Not a great manual page imo, but trust me on this one. Same issue when creating Triggers and Events.
I'm trying to find a way to check ,before adding a new tuple in a table, if the tuple respect some condition and in case of one of the conditions is not respected do not allow the insert.
I've thought of something like
DELIMITER //
CREATE TRIGGER t BEFORE INSERT ON Table
FOR EACH ROW
CALL CHECK1(…);
CALL CHECK2(…);
CALL CHECK3(…);
//
DELIMITER;
Where check1,check2,check3 are procedures that raise an exception if the NEW.(attributes) that I pass do not respect condition in the inserting table and/or with other tables.
Is this a correct and/or good way to make what I'm trying to do?
What is the best way to do that?
The best way to do it, is to do the data validation using stored procedures, instead of triggers. The trigger strategy is useful if you only want to filter incoming data. If the objective is to cancel an operation entirely when data values are unsuitable, you cannot do this in MySQL using a trigger.
I'm answering to reply(with a comment my answer would be incomprehensible) and to give more details:
I've used 2 strategies to make my goal, here 2 examples
1)if the check is easy
DELIMITER $$
create trigger RV5_1 before insert on Customer
for each row begin
IF(DATEDIFF(CURDATE(),NEW.birthdate)/365<18)
THEN
SIGNAL sqlstate '45006' set message_text = "too young to be a customer";
END IF;
END;
$$
DELIMITER ;
2) if the check is not easy and need cursors, variables etc
DELIMITER $$
create trigger T2 before insert on Table
for each row begin
IF (check1(NEW.[_some_attribute/s_]) or
check2(NEW.[_some_attribute/s_]))
THEN
SIGNAL sqlstate '45002' set message_text = "invalid insert";
END IF;
END;
$$;
DELIMITER ;
where check1 and check2 are stored functions that returns 0 if it's ok or 1 if there are problem with the new tuple.
Maybe someone with the same problem will found this helpful.
I need help converting this MS SQL update trigger to MySQL. My problem is with converting the MS SQL UPDATE() function, which identifies the specific columns that were updated:
ALTER TRIGGER [dbo].[tran_upd_action] ON [dbo].[tran_action]
FOR UPDATE AS
BEGIN
IF ##ROWCOUNT>0
BEGIN
IF update(column1) OR update(column2)
BEGIN
INSERT into tran_indexerqueue
(trankey, trkey2, tranname) SELECT tran_actionid, 0, 'tranaction' from inserted
END
END
END
This does not have the rowcount check, but the basic trigger syntax will be like this. Note that only the Super User role can create a trigger. Also, you have to change the delimiter first, which is usually a big gotcha for MSSQL DBAs.
DELIMITER $$
CREATE TRIGGER `tran_upd_action` AFTER UPDATE ON `tran_action` FOR EACH ROW BEGIN
INSERT INTO tran_indexerqueue
(trankey, trkey2, tranname)
VALUES(OLD.trankey, OLD.trkey2, OLD.tranname);
END $$
DELIMITER ;