I want to create a trigger that rejects the insert of an underage employee, by underage I mean that his year of birth is 2004 or more.
I wrote the following code, it runs without errors but then it doesn't let me insert any employee because it says :
ERROR: Unknown column 'BIRTHDATE' IN 'field list'
When I drop the trigger everything works fine.
DELIMITER $$
CREATE TRIGGER REJECT_EMP
BEFORE INSERT ON EMPLOYEE
FOR EACH ROW
BEGIN
IF YEAR(BIRTHDATE) > 2003 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred';
END IF;
END$$
DELIMITER ;
You should be testing NEW.BIRTHDATE
'Within the trigger body, the OLD and NEW keywords enable you to access columns in the rows affected by a trigger.' https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html
If you are running MySQL 8.0, I would recommend a check constraint rather than trigger logic.
alter table employee
add constraint chk_birthdate
check(year(birthdate) > 2003)
;
This enforces the same check that the trigger does, but the syntax is much shorter, and the logic is bundled directly in the definition of the table (so it is somehow easier to maintain). When an attempt is made to insert an offending row, you get the following error message:
Check constraint 'chk_birthdate' is violated.
I have to advice 2 changes in your trigger:
fist as #P.Salmon answered you should to use NEW.BIRTHDATE parameter
second use age instead birth-year in comparison
DELIMITER $$
CREATE TRIGGER REJECT_EMP
BEFORE INSERT ON EMPLOYEE
FOR EACH ROW
BEGIN
IF TIMESTAMPDIFF(YEAR, NEW.BIRTHDATE, NOW()) < 17 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred';
END IF;
END$$
DELIMITER ;
In general, the right way to check year() is on a day-by-day basis. So the logic that you want is:
BEGIN
IF BIRTHDATE > CURDATE() - INTERVAL 16 YEAR THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'An error occurred';
END IF;
END$$
This actually checks the date of birth. So someone can become an employee on their birthday.
I am not sure "16" is the right value, but your question doesn't explain it. It makes sense given the logic you have presented and that the year when you asked the question is 2020.
Related
after update user I get this error
ER_CANT_UPDATE_USED_TABLE_IN_SF_OR_TRG: Can't update table 'users' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
And this is my trigger, I want to remove user when his fame under 0
CREATE TRIGGER check_fame AFTER UPDATE ON users FOR EACH ROW
BEGIN
IF NEW.fame < 0 THEN
DELETE FROM users WHERE login = OLD.login;
END IF;
END
What is the error ?
If you want fame to always be positive, then use a check constraint:
ALTER TABLE users ADD CONSTRAINT chk_users_fame CHECK (fame >= 0);
A trigger is not needed for this operation in the more recent versions of MySQL.
In older versions you can use a trigger but you want to prevent the update:
CREATE TRIGGER check_fame BEFORE UPDATE ON users FOR EACH ROW
BEGIN
IF NEW.fame < 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Fame must never be negative';
END IF;
END;
I am a new to queries in dbms, so If someone could figure out what should be done here. Also, I am using Mysql.
code:
-> create trigger age_trigger before insert or update of age on employee
-> for each row
-> when( new.age <25)
-> begin
-> select 'Age can not be less than 25'
-> end;
error:
ERROR 1064 (42000): 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 'or update of age on employee for each row when(
new.age <25) begin select 'Age c' at line 1
You can't just come up with your own syntax :)
Have a look at the manual: CREATE TRIGGER Syntax
You can't specify multiple trigger_events. You need separate insert and update triggers. And this of age also has no business there.
All in all, what you're trying to do there can be done in MySQL (google for SIGNAL, if you insist), but best practice is, that this sort of logic is placed in the application layer. Don't put such logic in the database.
Below can be one of the option to implement BEFORE INSERT to obtain your desired result.
CREATE TRIGGER age_trigger
BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
IF NEW.age < 25
THEN SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Age can not be less than 25';
END IF;
END;
Similar syntax can be used for before update trigger.
DEMO
I have a mysql table:
`id` - int (primary key)
`datecolumn` - datetime
`name` - varchar
In my application, I want to enforce a rule that the name column can't be updated if the current date and time are past the datecolumn field's value. Currently, I'm querying the database for the value for each row, and then updating if the current date/time is before.
I'd like to know how to enforce this without the extra call to the database before updating. I'm updating many different rows at a time in the application, and think I'm causing performance issues because of all of the extra queries.
You can enforce rules like this using a trigger.
In your case, you would want a before update trigger. Something like this:
delimiter $$
create trigger noupdates before update on t
for each row
begin
if new.datecolumn > now() then
signal sqlstate '45000'
set message_text := 'Too late to update row';
end if;
end;
$$
delimiter ;
HOW to create SQL statement that UPDATE record in the table and after updated check whether
value is not negative if yes, throw ERROR!
Since I use TRANSACTION (ROLLBACK,COMMIT) I will use it to define whether should
I commit or rollback.
Thank in advance.
You can create a trigger that checks the value after each insert. It will fire an error if the column value is less than zero.
delimiter |
CREATE TRIGGER `check_value` AFTER UPDATE ON your_table
FOR EACH ROW BEGIN
IF NEW.value < 0 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'value can not be negative';
END IF
END
|
delimiter ;
I have a row in a table that I do not want to be changed (ever).
Is it possible to set a MySQL row to READ-ONLY so that it cannot be updated in any way? If so, how?
If not, is it possible to set a permanent value in one of the columns of that row so that it cannot be changed? If so, how?
Thanks.
This is likely to be business logic, which probably doesn't belong in your data storage layer. However, it can nonetheless be accomplished using triggers.
You can create a BEFORE UPDATE trigger that raises an error if a "locked" record is about to be updated; since an error occurs before the operation is undertaken, MySQL ceases to proceed with it. If you also want to prevent the record from being deleted, you'd need to create a similar trigger BEFORE DELETE.
To determine whether a record is "locked", you could create a boolean locked column:
ALTER TABLE my_table ADD COLUMN locked BOOLEAN NOT NULL DEFAULT FALSE;
DELIMITER ;;
CREATE TRIGGER foo_upd BEFORE UPDATE ON my_table FOR EACH ROW
IF OLD.locked THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Cannot update locked record';
END IF;;
CREATE TRIGGER foo_del BEFORE DELETE ON my_table FOR EACH ROW
IF OLD.locked THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Cannot delete locked record';
END IF;;
DELIMITER ;
UPDATE my_table SET locked = TRUE WHERE ...;
Note that SIGNAL was introduced in MySQL 5.5. In earlier versions, you must perform some erroneous action that causes MySQL to raise an error: I often call an non-existent procedure, e.g. with CALL raise_error;
I cannot create an additional column on this table, but the row has a unique id in one of the columns, so how would I do this for that scenario?
Again, if you absolutely must place this logic in the storage layer—and cannot identify the locked records through any means other than the PK—you could hard-code the test into your trigger; for example, to "lock" the record with id_column = 1234:
DELIMITER ;;
CREATE TRIGGER foo_upd BEFORE UPDATE ON my_table FOR EACH ROW
IF OLD.id_column <=> 1234 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Cannot update locked record';
END IF;;
CREATE TRIGGER foo_del BEFORE DELETE ON my_table FOR EACH ROW
IF OLD.id_column <=> 1234 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Cannot delete locked record';
END IF;;
DELIMITER ;
But this is absolutely horrible and I would do almost anything to avoid it whenever possible.