printing message in trigger Mysql 5.0 - mysql

WELL I NEED TO CREATE A TRIGGER ON TABLE RESERVATION IT DOES NOT ALLOW DATE LESS THAN CURRENT DATE.
MY TRIGGER IS :
mysql> create trigger reserve_trigger before insert on reservation
-> for each row
-> begin
-> if(new.Journey_Day<curdate())
-> then
-> set NEW="Jouney Date Should not be less than current date";
-> end if;
-> end //
Query OK, 0 rows affected (0.00 sec)
mysql> insert into reservation values ("ppno00005","FSA03","2012-02-09","ECONOMY","MC001","SC003")//
ERROR 1231 (42000): Variable 'new' can't be set to the value of 'Jouney Date Should not be less than current date'
I TRIED TO PRINT MESSAGE USING
signal sqlstate '45000' set message_text ="invalid entry";
BUT I REALIZED IT DOESN'T WORK FOR MY VERSION OF SQL. IS THERE A BETTER WAY OF DOING IT.

Yes, there is. You can call nonexistent stored procedure. For example -
...
BEGIN
IF NEW.Journey_Day < CURDATE() THEN
CALL proc_error_date();
END IF;
END
...

Related

Unable to delete a row using MySQL triggers

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.

"INSTEAD OF" in MySQL trigger, converted from SQL Server

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?

how programming a business rule on a trigger in mysql

I'm trying to programm a business rule in a trigger using MySQL, but it doesn't work.
What I want to do is that if the condition is false then the insert must fail and rollback it. The problem is that MySQL doesn't permit using rollback inside a trigger.
I've also tried to use SIGNAL and text message but it fails.
The code is:
CREATE TRIGGER tr_NewTeacher
AFTER INSERT ON teachers FOR EACH ROW
BEGIN
IF (salary > 1300 AND budget < 15000)
BEGIN
ROLLBACK TRANSACTION;
END
END
In MySQL trigger will rollback transaction if it fails.
So, you must raise exception within trigger body:
...
if [Test]
then
SIGNAL sqlstate '45001' set message_text = "No way ! You cannot do this !";
end if ;
...
You should be using before insert and for getting the column values you need to use new
So the trigger would be as
delimiter //
create trigger tr_NewTeacher before insert on teacher
for each row
begin
if new.salaRY>1300 AND new.budget<15000 then
signal sqlstate '45000' set message_text = 'Your error message';
end if;
end;//
delimiter ;
Here is a test case in mysql
mysql> create table teacher (id int auto_increment primary key,salaRY int , budget int);
Query OK, 0 rows affected (0.17 sec)
mysql> delimiter //
mysql> create trigger tr_NewTeacher before insert on teacher
-> for each row
-> begin
-> if new.salaRY>1300 AND new.budget<15000 then
-> signal sqlstate '45000' set message_text = 'Your error message';
-> end if;
-> end;//
Query OK, 0 rows affected (0.14 sec)
mysql> insert into teacher (salaRY,budget) values (1200,16000);
Query OK, 1 row affected (0.04 sec)
mysql> insert into teacher (salaRY,budget) values (1400,13000);
ERROR 1644 (45000): Your error message
mysql> select * from teacher ;
+----+--------+--------+
| id | salaRY | budget |
+----+--------+--------+
| 1 | 1200 | 16000 |
+----+--------+--------+
1 row in set (0.00 sec)

Error in Creation of Stored Procedure

CREATE PROCEDURE `go`()
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN DECLARE d_z CONDITION FOR SQLSTATE '35241';
SELECT COUNT(*)as #a from _time
IF #a>0 THEN
SIGNAL d_z SET MESSAGE_TEXT='errrrrrrrrrrrr';
END IF;
END;
error:SQL Error (1064): 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 '#a from _time
IF #a>0 THEN SIGNAL d_z SET MESSAGE_TEXT='errrrrrrrrrr' at line 9
The problem is with the select statement "#a" is alias name which cant be used further queries.
You can use peterm query "into" instead of as
Hope this helps
Happy Coding
You has some syntax issues. Following works for me:
DELIMITER //
CREATE PROCEDURE `go`()
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE d_z CONDITION FOR SQLSTATE '35241';
select count(*) INTO #a from _time;
IF #a>0 THEN
SIGNAL d_z SET MESSAGE_TEXT='errrrrrrrrrrrr';
END IF;
END
//
Important is to:
Use into #variable syntax for selecting a value into a var
Use DELIMITER for termination of multiline procedure body
Your immediate error is caused by the malformed SELECT statement. You have to a proper SELECT INTO syntax
Change
SELECT COUNT(*)as #a from _time
to
SELECT COUNT(*) INTO #a FROM _time
^^^^
Now there are several other issues with your code:
There is no need to use a user(session) variable, you could've used local variable instead
You don't want to get total number of all rows just to tell whether you have rows or not in your table. If you do you'll pay performance penalty (if of course you're not using MyISAM). You can leverage NOT EXISTS() for that or LIMIT 1 clause.
That being said a streamlined version of your procedure might look like
DELIMITER $$
CREATE PROCEDURE `go`()
BEGIN
DECLARE d_z CONDITION FOR SQLSTATE '35241';
IF NOT EXISTS(SELECT * FROM _time) THEN
SIGNAL d_z SET MESSAGE_TEXT='errrrrrrrrrrrr';
END IF;
END$$
DELIMITER ;
Here is SQLFiddle demo
Let's give it a try
mysql> CREATE TABLE _time (`id` int);
Query OK, 0 rows affected (0.03 sec)
mysql> DELIMITER $$
mysql> CREATE PROCEDURE `go`()
-> BEGIN
-> DECLARE d_z CONDITION FOR SQLSTATE '35241';
-> IF NOT EXISTS(SELECT * FROM _time) THEN
-> SIGNAL d_z SET MESSAGE_TEXT='errrrrrrrrrrrr';
-> END IF;
-> END$$
Query OK, 0 rows affected (0.02 sec)
mysql> DELIMITER ;
mysql> CALL go();
ERROR 1644 (35241): errrrrrrrrrrrr

when i signal something like '01%' i don't get a warning

After this trigger i dont get a warning if i inserted 5 in foo.x
\d $
CREATE TRIGGER `tri` BEFORE INSERT ON `foo` FOR EACH ROW
BEGIN
IF NEW.bar = 5 THEN
SIGNAL SQLSTATE '01002' SET MESSAGE_TEXT = 'MSG';
END IF;
END$\d ;
INSERT INTO `foo` values (5);
1 row affected
As documented under Changes in MySQL 5.5.8 (2010-12-03, General Availability):
Bugs Fixed
[ deletia ]
Warnings raised by a trigger were not cleared upon successful completion. Now warnings are cleared if the trigger completes successfully, per the SQL standard. (Bug #55850)
Are you sure that trigger was created? I have got two errors.
Try to use this statement instead -
SIGNAL SQLSTATE '01002' SET MESSAGE_TEXT = 'MSG';
'010002' -> '01002'
TEXT_MESSAGE -> MESSAGE_TEXT
SIGNAL Syntax.