I'm trying to create a trigger which does a ROLLBACK TRANSACTION as soon as a certain value is reached in a table.
Imagine that a Student of a uni library is only able to have 5 active loans simultaneously. How would I implement that kind of trigger?
This is what we have so far:
CREATE DEFINER = CURRENT_USER TRIGGER `bib_db`.`Customer_AFTER_UPDATE` AFTER UPDATE ON `Customer` FOR EACH ROW
if activeloans <5
AND Customertype = student
then
SIGNAL sqlstate '45001' set message_text = "You've reached your maximum ammount of loans";
ROLLBACK TRANSACTION
end if ;
end
I might be way off, but this is as far as i've got...Anyone got any ideas?
Two important things. First, you should use a before update trigger to prevent the update from happening. Second, the logic is backwards. Something more like:
DELIMITER //
CREATE DEFINER = CURRENT_USER TRIGGER bib_db.Customer_BEFORE_UPDATE
BEFORE UPDATE ON `Customer`
FOR EACH ROW
BEGIN
if activeloans >= 5 AND Customertype = 'student' then
SIGNAL sqlstate '45001' set message_text = "You've reached your maximum ammount of loans";
end if ;
END;
DELIMITER ;
end
Related
I have a trigger in MySQL
DELIMITER $$
CREATE TRIGGER trigger2
BEFORE INSERT ON participated FOR EACH ROW
BEGIN
IF((SELECT COUNT(*) FROM participated WHERE driver_id = NEW.driver_id) > 3) THEN
DELETE FROM accident WHERE report_no = NEW.report_no;
SIGNAL SQLSTATE '45000' SET message_text = "Driver is already involved in 3 accciddents";
END IF;
END;$$
DELIMITER ;
First an accident report is inserted into accident table. Before inserting in to participated table if it involves a driver who has participated in more than 3 accident a waring has to be given and driver's data in accident table should be deleted.
'accident' and 'participated' are the two tables.
accident(report_no,date,location);
participated(driver_id,reg_no,report_no,amount);
ex:
insert into accident values(34,"2022-04-05","bangalore");
insert into participated values("D1","KA-09-MM-5644",34,20000);
ERROR 1644 (45000): Driver is already involved in 3 accciddents
Warning is working but it is not deleting the row in accident table. accident table still has the row with report_no 34
The body part in Mysql trigger is like a single ALL-OR-NOTHING transaction. This means every query inside has to be successful, or the entire process is undone. By using SIGNAL SQLSTATE '45000' SET message_text , an error is intentionally raised, which rolls back every thing that has happend so far, and a message is returned. Note, the INSERT statement itself is cancelled due to error induced. Of course, it's possible to ignore the error by declaring a continue handler in the very begining of the trigger.
BEGIN
declare continue handler for SQLSTATE '45000' begin end;
IF((SELECT COUNT(*) FROM participated WHERE driver_id = NEW.driver_id) > 3) THEN
DELETE FROM accident WHERE report_no = NEW.report_no;
SIGNAL SQLSTATE '45000' SET message_text = "Driver is already involved in 3 accciddents";
END IF;
END
This will make sure things keep going after SQLSTATE '45000' is encountered. However, the message_text is IGNORED, as it's only intended to show up to address a warning/error, not for a continue handler. And regrettably, we can not return a result set using a trigger. So if we add a SELECT statement or something alike after the SIGNAL statement , an error will pop up:
select "Driver is already involved in 3 accciddents" as a warning;
-- OR
show warnings;
-- Error Code: 1415. Not allowed to return a result set from a trigger
If we really need a message to show up,we can considering using a procedure to bypass the restriction enforced by trigger:
DELIMITER $$
CREATE TRIGGER trigger2
BEFORE INSERT ON participated FOR EACH ROW
BEGIN
IF((SELECT COUNT(*) FROM participated WHERE driver_id = NEW.driver_id) > 3) THEN
DELETE FROM accident WHERE report_no = NEW.report_no;
SET #warning = "Driver is already involved in 3 accciddents"; -- here we don't really need a SIGNAL statement. Just creating a user variable is adequate.
else set #warning=null;
END IF;
END$$
create procedure insert_participated (d_id varchar(20),rg_no varchar(20),rp_no int,amt int)
begin
insert into participated values(d_id,rg_no,rp_no,amt);
if #warning is not null then
select #warning as warning;
end if;
end $$
DELIMITER ;
By using a procedure ,we can display a message. And if we directly use an insert statement(when we forget to use the procedure), the trigger's operation still applies. Therefore, we might think about adding an INSERT statement to populate an auditing table for future reference.
I want to use Trigger in Mysql to be able to control "evaluation_weight" column in "evaluation_criteria" table. If the sum of the "evaluation_weight" column >= 100 after update/insert, it will not be possible to update/insert the newly entered value.
Here is the picture of "evaluation_criteria" table
You would need two triggers with one for update and another one for insert.
delimiter //
drop trigger if exists check_evaluation_insert ;
create trigger check_evaluation_insert before insert on evaluation_criteria for each row
begin
if (select ifnull(sum(evaluation_weight),0) from evaluation_criteria) + new.evaluation_weight>= 100 then
signal SQLSTATE VALUE '99999' SET MESSAGE_TEXT = 'The limit of evaluation_weight has been reached. INSERT fails. ';
end if;
end//
drop trigger if exists check_evaluation_update ;
create trigger check_evaluation_update before update on evaluation_criteria for each row
begin
if (select ifnull(sum(evaluation_weight),0) from evaluation_criteria) + new.evaluation_weight - old.evaluation_weight>= 100 then
signal SQLSTATE VALUE '99999' SET MESSAGE_TEXT = 'The limit of evaluation_weight has been reached. UPDATE fails. ';
end if;
end//
delimiter ;
I'm in the process of converting some SQL Server triggers to MySQL, and am running into some syntax issues. The rest of the database schema and objects were converted using the AWS Schema Conversion Tool, as I'm migrating a SQL Server database to Aurora RDS MySQL. Here's an example of a trigger I'm having trouble converting:
-- Create the UpdateAUD trigger on the new table.
CREATE TRIGGER [dbo].[UpdateAUD] ON [dbo].[AUD]
INSTEAD OF UPDATE
AS
BEGIN
IF ##ROWCOUNT > 0
BEGIN
RAISERROR( 'Audit rows for AUD cannot be updated!', -1, 0 );
ROLLBACK;
END
END;
The code that I've tried looks like:
DELIMITER $$
-- Create the UpdateAUD trigger on the new table.
CREATE TRIGGER dbo.UpdateAUD
AFTER UPDATE
ON dbo.AUD FOR EACH ROW
BEGIN
set msg = ('Audit rows for AUD cannot be updated!');
signal sqlstate '45000' set message_text = msg;
ROLLBACK;
END$$
First, does AFTER work to replace INSTEAD OF? Secondly, MySQL workbench is having an issue with the RAISERROR, which I've looked up workarounds for. However the error I'm getting is around theh msg variable where it's saying Unknown system variable 'msg'
Any ideas?
It has to be a BEFORE UPDATE TRIGGER, so that the UPDATE is interupted
You could also
REVOKE UPDATE ON AUD FROM '*'#'localhost';
and so nobody could UPDATE the table anymore
CREATE TABLE AUD (id int)
INSERT INTO AUD VALUES(1)
CREATE TRIGGER UpdateAUD
BEFORE UPDATE
ON AUD FOR EACH ROW
BEGIN
set #msg := 'Audit rows for AUD cannot be updated!';
signal sqlstate '45000' set message_text = #msg;
END
✓
UPDATE AUD SET id = 1 WHERE id = 1
Audit rows for AUD cannot be updated!
db<>fiddle here
I ended up revising to
DELIMITER $$
-- Create the UpdateAUD trigger on the new table.
CREATE TRIGGER dbo.UpdateAUD
BEFORE UPDATE
ON dbo.AUD FOR EACH ROW
BEGIN
signal sqlstate '45000' set message_text = 'Audit rows for AUD cannot be updated!';
END$$
Per documentation, there's no need for ROWCOUNT since FOR EACH ROW should handle that. As far as the ROLLBACK goes, I checked https://dev.mysql.com/doc/refman/5.6/en/trigger-syntax.html and saw that it should be handled as well.
Does this look like a good conversion from the original MS-SQL posted at the top?
I am having problems implementing a trigger into my table. I am using MySQL, Phpmyadmin
Scenario: Table User(user_id, name, surname, date_of_joining), record(record_id, date_of_record, weight, height, id_user)
a user can have multiple records which show his weight and height at a certain date. id_user is a foreign key referencing to user_id.
I am trying to implement a trigger for insert and update which checks if date_of_record is greater than date_of_joining, if not, the insert should be stopped.
This is a trigger I tried and the insert still goes through
CREATE TRIGGER date_check_insert BEFORE INSERT ON record
FOR EACH ROW
BEGIN
DECLARE date_of_registering DATE;
SET date_of_registering = (SELECT date_of_registering FROM user WHERE user_id = new.id_user);
IF (new.date_of_record NOT BETWEEN date_of_registering AND CURDATE()) THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = "Can not insert that value";
END IF;
END
Any help is appreciated
I'd slightly change the trigger:
Use session variable (so no DECLARE needed)
Put comparison logic in a single place in the WHERE clause (easier to read & understand)
Shows reason in error message
Use SELECT INTO variable instead of SET variable = query (not necessary, I just prefer this way)
So:
CREATE TRIGGER date_check_insert BEFORE INSERT ON record
FOR EACH ROW
BEGIN
SET #found = NULL;
SELECT
user_id INTO #found
FROM
user
WHERE
user_id = NEW.id_user
AND NEW.date_of_record BETWEEN date_of_registering AND NOW() -- or CURDATE() depend on your datetype
;
IF #found IS NULL THEN
SET #msg = CONCAT('Can not insert. Out of range value ', NEW.date_of_record);
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = #msg;
END IF;
END
I am using Mysql and trying to create a trigger on a table that prevents a specific record from being deleted or updated, example I have a table demo
id username password
1 dames t312llok
2 sauce 12ff1fff1
3 hynes 5656166oo9
I would like to prevent the record:
id username password
1 dames t312llok
from being deleted or updated via the use of a trigger
If you are using MySQL 5.5 or higher, this is simple.
DELIMITER $$
DROP TRIGGER IF EXISTS demo_bd $$
CREATE TRIGGER demo_bd BEFORE DELETE ON demo FOR EACH ROW
BEGIN
IF OLD.id = 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'This magical user cannot be deleted';
END IF;
END $$
DELIMITER ;
For the update, it's exactly the same code, with minor tweaks.
DELIMITER $$
DROP TRIGGER IF EXISTS demo_bu $$
CREATE TRIGGER demo_bu BEFORE UPDATE ON demo FOR EACH ROW
BEGIN
IF OLD.id = 1 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'This magical user cannot be updated';
END IF;
END $$
DELIMITER ;
Also... don't store passwords in the database.