Is it possible to declare that a column in MySQL should be unmodifiable once initially set? I have a column that has the following definition: created timestamp default current_timestamp and I'd like to make sure that nobody messes with it after my rows are created.
You can accomplish this using a BEFORE UPDATE trigger:
DELIMITER $$
CREATE TRIGGER trFoo BEFORE UPDATE ON foo
FOR EACH ROW BEGIN
IF NEW.Bar != OLD.Bar THEN
SET NEW.Bar = OLD.Bar;
END IF;
END$$
DELIMITER ;
Related
I am trying to update a column ( called DateModified ) before update happens on the table row.
so here is my trigger:
CREATE TRIGGER `date_mod_category` BEFORE UPDATE ON `categories`
FOR EACH ROW BEGIN
SET new.DateModified = NOW();
END
BUT I GET THIS DAMN ERROR WHICH I JUST CANNOT FIGURE OUT WHY:
Use DELIMITER
DELIMITER //
CREATE TRIGGER `date_mod_category` BEFORE UPDATE ON `categories`
FOR EACH ROW
BEGIN
SET new.DateModified = NOW();
END //
DELIMITER ;
I want a trigger which compare two datetime.
Here my trigger:
EDIT :
create trigger updateRealisee after update on ladi.DSMSreservation for each row
begin
declare mnt datetime;
mnt=(select NOW());
if :new.date < mnt then
:new.realisee = 1;
end if;
end;
The error is that there are several restrictions on an after udpate trigger:
You can not create an AFTER trigger on a view.
You can not update the NEW values.
You can not update the OLD values.
However, you can change it to a before insert trigger.
I have tested the code below and it works. Of course, it only works on those you are newly inserting, not ones that already exist. For the ones that already exit.... simply run:
update TEST.DSMSreservation set realisee = 1 where date < NOW();
Then... the following complete code to create a table, trigger, and add rows provides an example how it works on newly added rows:
create database TEST;
USE TEST;
CREATE TABLE TEST.DSMSreservation
(
date DATETIME NULL DEFAULT NULL,
realisee INT NULL DEFAULT NULL
);
delimiter $$
create trigger updateRealisee before insert on TEST.DSMSreservation
for each row
begin
IF (new.date < NOW()) THEN
SET new.realisee = 1;
end if;
end;
$$
delimiter ;
INSERT INTO DSMSreservation VALUES ('2012-06-08 12:13:14',0);
INSERT INTO DSMSreservation VALUES ('2017-06-08 12:13:14',0);
INSERT INTO DSMSreservation VALUES ('2016-06-08 10:13:14',0);
INSERT INTO DSMSreservation (date) VALUES ('2016-06-08 16:13:14');
Running these two mysql statements will resolve what you were trying to accomplish with your original trigger.
Please mark as answer if this has answered your question.
I hav a table with several fields. One field is "date_assigned" and the other is "assigned". "date_assigned" has a datatype of timestamp and can be null. "assigned" has a datatype of tinyint and the values are either 0 (default; 'not assigned') or 1 ('assigned').
I would like to create a trigger that would automatically update the "assigned" value to 1 when "date_assigned" is updated with a value (is not null).
I've used triggers before, but have not used them in conjunction with checking if a value is null. I'm unclear on the syntax, so any help would be appreciated. So far, I've tried:
DELIMITER $$
CREATE
TRIGGER `<database>`.`<trigger_name>` AFTER UPDATE
ON `<database>`.`<table>`
FOR EACH ROW BEGIN
IF(NEW.date_assigned IS NOT NULL) THEN
UPDATE <table> SET assigned = '1';
END$$
DELIMITER ;
I just get Error Code: 1064. I looked upo the code, and it appears that it's a syntax error. So what syntax mistake am I making, and is this even the correct 'grammar'?
Try putting BEGIN in a new line as follows.
DELIMITER $$
CREATE
TRIGGER `<database>`.`<trigger_name>` AFTER UPDATE
ON `<database>`.`<table>`
FOR EACH ROW
BEGIN
IF(NEW.date_assigned IS NOT NULL) THEN
UPDATE <table> SET assigned = '1';
END; //Change here also.
$$
DELIMITER ;
This is because of default delimiter in MySQL set to ;. So, the first line should look like DELIMITER $$;
DELIMITER $$;
CREATE TRIGGER `<database>`.`<trigger_name>`
AFTER UPDATE ON `<database>`.`<table>`
FOR EACH ROW BEGIN
IF(NEW.date_assigned IS NOT NULL) THEN
UPDATE <table> SET assigned = '1';
END$$
DELIMITER ;
I'm using mysqlimport to do mass table inserts (replacing duplicates primary keys). Several tables have date time columns with records containing values '0000-00-00'. What I would like is a trigger which detects these '0000-00-00' values and replaces with '1950-01-01', otherwise keep the datetime value in the record (i.e. when it's not '0000-00-00').
I have tried the following:
CREATE TRIGGER set_datetime BEFORE INSERT ON tbl
FOR EACH ROW
CASE
WHEN date_col='0000-00-00' THEN SET date_col='1950-01-01';
END CASE
Thank you.
EDIT
Update attempt:
CREATE TRIGGER set_datetime BEFORE INSERT ON tbl
FOR EACH ROW
IF (NEW.date_col='0000-00-00') THEN
SET NEW.date_col='1950-01-01';
END IF;
Still getting an error in the SET portion.
EDIT 2
WORKING:
DELIMITER $$
CREATE TRIGGER insert_check BEFORE INSERT ON ar
FOR EACH ROW
BEGIN
IF NEW.delivery_date='0000-00-00' THEN
SET NEW.delivery_date='1950-01-01';
END IF;
END; $$
DELIMITER ;
Use IF THEN :
IF (NEW.date_col = '0000-00-00') THEN
SET NEW.date_col='1950-01-01';
END IF;
CREATE TRIGGER set_datetime BEFORE INSERT ON tbl
FOR EACH ROW
IF YEAR(NEW.date_col)=0 THEN
SET NEW.date_col='1950-01-01 00:00:00';
END IF;
Give it a Try !!!
If you want, or need, to use 'case' then this should work:
SET NEW.date_col=CASE WHEN NEW.date_col='0000-00-00' THEN ='1950-01-01'
WHEN NEW.date_col='something else' THEN 'whatever'
ELSE 'default'
END CASE;
Currently, I have bunch of triggers that do the same thing. This is copy-pasted for every table that needs this functionality.
delimiter $$
create trigger user_before_insert before insert on user for each row
begin
set NEW.create_time = CURRENT_TIMESTAMP;
set NEW.create_user_id = #user_id;
set NEW.modify_time = CURRENT_TIMESTAMP;
set NEW.modify_user_id = #user_id;
end$$
create trigger user_before_update before update on user for each row
begin
set NEW.modify_time = CURRENT_TIMESTAMP;
set NEW.modify_user_id = #user_id;
end$$
Is it possible to wrap the lines that modify OLD and/or NEW into stored procedures that are called via triggers? Something like this:
delimiter $$
create procedure autofill_on_insert(inout NEW data_type) -- what would be the data_type?
begin
set NEW.create_time = CURRENT_TIMESTAMP;
set NEW.create_user_id = #user_id;
set NEW.modify_time = CURRENT_TIMESTAMP;
set NEW.modify_user_id = #user_id;
end$$
create procedure autofill_on_update(inout NEW data_type) -- what would be the data_type?
begin
set NEW.modify_time = CURRENT_TIMESTAMP;
set NEW.modify_user_id = #user_id;
end$$
delimiter ;
create trigger user_before_insert before insert on user
for each row call autofill_on_insert(NEW);
create trigger user_before_update before update on user
for each row call autofill_on_update(NEW);
Additional question: if this is possible, is there any way to check if NEW contains specific columns? There are tables that do not have modify_time and modify_user_id.
I can say that NEW cannot be passed into the procedure, because NEW is an alias that represents a row. Procedure's arguments have to be scalar values, like INT, VARCHAR, etc..
About the 'SET NEW.create_time = CURRENT_TIMESTAMP;'; if field create_time is a TIMESTAMP, you could set CURRENT_TIMESTAMP as default value for it.