mysql: Insert only if certain conditions are respected - mysql

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.

Related

Why is this trigger not being created?

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.

Adding comments/notes

I have a trigger as follows:
DELIMITER //
create trigger highStockInsert
After insert on inventory
for each row Begin
if new.currentStock > 250 then Insert INTO higherStockList VALUES (new.prodName, new.StockCount, new.storeName, 'High Alert');
end if; end
// ;
Now when this trigger is act upon I would like mysql to give a message of some sorts, I was messing around with SQLSTATE but if this is triggered the table doesn't update it just blocks the whole insert statement from going through. I was wondering if its possible for the new row to be added but still give off a notification. I was looking if its possible to trigger a warning but found no luck either.
Thanks!

Unexpected END_OF_INPUT in MySQL trigger

I have searched for all the possible online solutions but I can't figure out the error in this trigger.
CREATE TRIGGER `delete_neat_link`
AFTER DELETE ON `neat_urls`
FOR EACH ROW
BEGIN
DELETE FROM `css_paths`
WHERE `css_paths`.`path_id` = OLD.`neat_link`;
END;
the first error appears at OLD.neat_link
syntax error, unexpected END_OF_INPUT, expecting ';'
and the second one at END;
syntax error, unexpected END
Any help would be appreciable, thanks.
That problem is due to interpreting individual statements. The CREATE TRIGGER statement is as such a single complete statement that must be sent as is to the server. Usually statement borders are recognized by the default delimiter (the semicolon). In case of stored programs however the semicolon is needed to separate inner statements. This would confuse the client as it cannot tell apart what is an inner statement of the stored program or a full statement as it must be sent as a whole to the server.
Hence the DELIMITER statement was introduced which only applies to clients (not the server, the server itself cannot parse this statement). It changes the default delimiter to one of your choice, leading so the client where to look for the statement's end. A typical case hence looks like this:
DELIMITER ;;
CREATE TRIGGER `ins_film` AFTER INSERT ON `film` FOR EACH ROW BEGIN
INSERT INTO film_text (film_id, title, description)
VALUES (new.film_id, new.title, new.description);
END;;
Their is only one statement in the body of the Trigger, so there is no need to use the BEGIN-END compound statement construct. Try this:
CREATE TRIGGER `delete_neat_link`
AFTER DELETE ON `neat_urls`
FOR EACH ROW
DELETE FROM `css_paths`
WHERE `css_paths`.`path_id` = OLD.`neat_link`
another possible solution
DELIMITER $$
CREATE TRIGGER `delete_neat_link`
AFTER DELETE ON `neat_urls`
FOR EACH ROW
BEGIN
DELETE FROM `css_paths`
WHERE `css_paths`.`path_id` = OLD.`neat_link`;
END$$
DELIMITER ;

Protect column, disallow update, only allow insert if NULL in MySQL

I want to protect existing dates in a date column from being overwritten. So disallow updates to the date column and only allow inserts if the existing field value is NULL (date column default is NULL). Are triggers the only way to accomplish this in MySQL? If so, would the trigger below work?
create trigger date_check
before insert, update on date
for each row
begin
if(date IS NOT NULL) then
SIGNAL 'date already set'
end if ;
end ;
Background: I have a table with critical dates that was accidentally changed due to user error. I put some checks in the user interface to prevent this from happening again but want another layer of safety directly with the database if possible.
Yes, in MySQL triggers are the only way to do this. MySQL does not support constraints.
Your trigger is not exactly right. First, you have update on date, but this should be update on <table name>. Second, you are checking the date value used for the update. Perhaps you mean:
create trigger date_check_update
before update on <the table name goes here>
for each row
begin
if (old.date IS NOT NULL) then
SIGNAL 'date already set'
end if ;
end;
An insert trigger on this condition doesn't make sense.
If anyone like me stumble upon this thread and is getting syntax error, it's because "When you try to raise errors via SIGNAL you need to specify the SQLSTATE which is the error code and for the user defined generic error codes its 45000 along with the message text MESSAGE_TEXT"
So the SIGNAL line should look like this.
signal SQLSTATE VALUE '45000' SET MESSAGE_TEXT = 'Your custom error message';
See this answer for more details.
https://stackoverflow.com/a/42827275/4164651
Just combining the above two answers, however, if you are writing triggers directly at the terminal, you'll have to change the delimiter before writing the trigger and then change it back once done.
delimiter $$
create trigger date_check_update
before update on <the table name goes here>
for each row
begin
if (old.date IS NOT NULL) then
signal SQLSTATE VALUE '45000' SET MESSAGE_TEXT = 'Your custom error message';
end if ;
end $$
delimiter ;

update trigger to maintain correct url in field

I am seeking a short term solution while I work out why a synchronisation is setting one field wrong in a table
I prepared a trigger and would welcome some comment on it, and any necessary corrections or better strategies.
CREATE TRIGGER urlcorrect AFTER INSERT ON sym_node
FOR EACH ROW BEGIN
IF NEW.sync_url= 'http://wrongaddress' THEN
UPDATE sym_node SET sync_url= "http://123.456.7.89:1234/etc";
END IF;;
END$
delimiter;
thanks
David
Your trigger is wrong in various ways.
First of all, I think you want a BEFORE trigger so that you can fix the row before it gets into your table.
Secondly, this:
UPDATE sym_node SET sync_url= "http://123.456.7.89:1234/etc";
would update every sync_url in the sym_node table and that's not what you want. And I don't think MySQL will let you UPDATE a table inside a trigger on that table (someone correct me if I'm wrong on this please). Also, you should be using single quotes for string literals even though MySQL will let you use double quotes, don't pick up bad habits from MySQL lax behavior. You want to:
set new.sync_url = 'http://123.456.7.89:1234/etc';
Putting all that together, you get this:
delimiter $
create trigger urlcorrect before insert on sym_node
for each row begin
if new.sync_url = 'http://wrongaddress' then
set new.sync_url = 'http://123.456.7.89:1234/etc';
end if;
end;
$
delimiter ;