I have this reservation table that has RESERVATION_ID , ROOM_NUM, Date_Start , Date_End and cost columns. what I want to do is insert all the columns except cost and fill the cost automatically.
delimiter //
CREATE TRIGGER upd_check before INSERT ON reservation
FOR EACH ROW
BEGIN
IF NEW.RESERVATION_COST = NULL THEN
SET NEW.RESERVATION_COST = 'timestampdiff(day, NEW.RESERVATION_STARTD, NEW.RESERVATION_ENDD)*70';
END IF;
END;//
delimiter ;
I wrote this trigger to do it, but whenever I press Apply to insert everything nothing is inserted to the RESERVATION_COST column.
why?
I would put this in a comment if I had enough reputation, but anyways. Triggers cannot act on the same table which activated them. Seems limiting, but we've had the same issue.
This link doesn't explicitly say this but it does say "in the associated table". Not the same: https://dev.mysql.com/doc/refman/5.0/en/triggers.html
You can't compare a value to NULL, you need to check if it IS NULL instead.
e.g.
IF NEW.RESERVATION_COST IS NULL THEN
Related
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 ;
I have a question about MySQL triggers—say I have the following table:
CREATE TABLE test (
id INT(6),
value_1 INT(6),
value_2 INT(6),
values_were_set BOOL
)
Now, every time I insert a value into this table I want to have a trigger check if value_1 and value_2 have been set. And if they are, it should set values_were_set to true.
NULL values are allowed.
How would I go about this? In the real table there are about ten columns that I want to check for, so I would fancy not to have to use a bunch of IF statements.
Maybe it's better to do it in the app?
Then trigger it is:
DELIMITER $$
CREATE TRIGGER value_check BEFORE INSERT ON test
FOR EACH ROW
BEGIN
IF NEW.value_1 IS NOT NULL AND NEW.value_2 IS NOT NULL THEN
SET NEW.values_were_set = 1;
ELSE
SET NEW.values_were_set = 0;
END IF;
END;
$$
Unfortunately yes, I think you would need a nasty if/else section in the trigger if you want to check multiple combinations of fields
Hi I want to create trigger if it's condition satisfy then it's body should be executed and I want to display some message or any data that should be displayed if trigger body executed.
I want that if quantity of product went less then 50 then it should display message or some data.
Is it possible to display message ?
Here testdata is table name.
Code :
delimiter //
create trigger trigger2 before update on test.testdata
for each row
begin
if new.qty < 50 then
**display here some message that quantity is less**
end if;
end;
//
delimiter ;
You cannot do it, there is no place to output them in MySQL. As a work around you can add your message to the table, and then read this table.
Short example -
CREATE TABLE table1 (
column1 VARCHAR(255) DEFAULT NULL
);
CREATE TABLE messages (
id INT(11) NOT NULL AUTO_INCREMENT,
message VARCHAR(255) DEFAULT NULL,
time TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
DELIMITER $$
CREATE TRIGGER trigger1
AFTER INSERT
ON table1
FOR EACH ROW
BEGIN
INSERT INTO messages(message) VALUES ('new action');
END
$$
DELIMITER ;
Also, you could use UDF function write your logic.
More information - CREATE FUNCTION Syntax for User-Defined Functions.
For Quick and plain answering: You cannot Display Messages From Triggers. You may Only Throw errors.
You are propably not knowing the reason u use triggers in databases assuming from your question. We all have passed that level so dont worry. U have understood the syntax when we use triggers but not how and what they can do and not.
A trigger will do (for your case BEFORE an UPDATE) something concerning the database and only that.
That means the trigger cannot display any message on your screen. You can only handle database staff and not all of the actions are allowed for that too or some actions arent even recommended!.
That is for the theory part.
To give you a solution to your problem now.
The only thing you can do to know when the trigger has worked (that means when the new.qua<50) or basically check anything with any other trigger is the following. (Just a small fast solution):
You need to create a Table that will handle all logging of the
triggers.
Add in it an ID field, a descr field that will hold the action of
the triggerex. BefUpdate, BefInsert etc. another field for the
propably the condition that triggered the logging and antyhing else
u want displayed later in the application.
Then inside the if condition u are using write and insert
statemement to fill the info in the new (logging) table.
in your app later select that logging table to see the messages.
That is a useful and fast way to log, not only triggers but also functions (stored procs).
Judt for reference i give you s sample code with the CREATE, and the INSERT statement for your trigger.
CREATE TABLE LOGGER (
ID BIGINT PRIMARY KEY AUTO_INCREMENT,
DESCR_ACTIVITY VARCHAR(10),
ACTIVITY VARCHAR(50),
DT TIMESTAMP,
CONDITIONVALUE VARCHAR(50)
)
In the IF of your code now make it as :
if new.qty < 50 then
INSERT INTO LOGGER VALUES ('BEFINS','CHECKING QUA',NULL,'QUANTITY IS LOWER THAN 50')
end if;
And even from the workbench or from your application u can just :
SELECT * FROM LOGGER
to see the loggings.
But if i am confused from the reading and you want just to throw an error u can read the Mysql Documentation concerning throwing errors:
enter link description here
What u can do is in your if condition write something like:
if new.qty < 50 then
SIGNAL SQLSTATE '01000' SET MESSAGE_TEXT = 'Lower than 50', MYSQL_ERRNO = 1000;
endif;
What u should always NOT DO is alter the same table that a trigger is assigned and use only small portion of not so complex code in the trigger.
Hope i helped a bit.
Also, you can display any message using the select command.
IF (NEW.qty < 50) THEN
SELECT "message that quantity is less" AS Output;
END IF
Place above code inside the trigger. It will print the output
I'd like to make a TIMESTAMP field DEFAULT CURRENT_TIMESTAMP, for 'creation time' purpose. But if someone or somehow something changes that TIMESTAMP, my data won't be consistent.
Is there a way I can ensure it won't change unless I delete the row and reinsert it, other than application level?
With the suggested answer provided, i could work around with something like this
CREATE TRIGGER consistency1 BEFORE UPDATE ON table1
FOR EACH ROW
BEGIN
IF NEW.creationtime != OLD.creationtime THEN
SET NEW.creationtime = OLD.creationtime;
END IF;
END;
Since my comment has been appreciated, here's the extended version.
I personally don't think that it's possible.
Anyway, there are a couple of things you can try:
Make sure that only your application can write on the database
Write a trigger like this (pseudocode!)
create trigger prevent_change_timestamp on tbl_name
before update
#fetch old row value
#verify if the timestamp field has been changed
#raise an error (any SQL error will do)
Or like this
create trigger revert_change_timestamp on tbl_name
after update
#fetch pre-change row value
#update the row with the "old" value in place of the new one
I'd personally go with the 3rd option, if possible. Anyway, the 2nd one is good too. I'd not rely on the 1st option unless necessary (eg: no access to trigger functionality)
More info here: reference
It's funny in a way that database apps don't offer this functionality as standard: not only for a "created" timestamp field, but for things like autoincrement id fields, and any miscellaneous values which you may want to set on creating a record and then never allow to be changed... wonder what the rationale is?
What you can do here is, you can write a TRIGGER on the table when a row is being updated. In that trigger, you can compare the old and new values, and if they are different then you can just overwrite the new value with the old one.
I tried this in MySQL 5.1 and got an error
DELIMITER //
CREATE TRIGGER member_update_0
-> AFTER UPDATE ON members
-> FOR EACH ROW
-> BEGIN
-> IF NEW.id != OLD.id THEN
-> SET NEW.id = OLD.id;
-> END IF;
-> END;//
ERROR 1362 (HY000): Updating of NEW row is not allowed in after trigger
The same trigger with AFTER replaced by BEFORE is accepted;
to me, this is a counter-intuitive way to do it, but it works
delimiter ;
UPDATE members SET id=11353 WHERE id=1353;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
It is actually possible to do this very neatly if you are using InnoDB.
Create another table with just one column. That column should have a foreign key (hence the innodb requirement in this solution) that points to the immutable column of the original table in question.
Put a restriction like "ON UPDATE RESTRICT".
In summary:
CREATE TABLE original (
....
immutable_column ...
INDEX index1(immutable_column)
....
) ENGINE=INNODB;
CREATE TABLE restricter (
.....
col1,
INDEX index2(col1),
FOREIGN KEY (col1) REFERENCES original (immutable_colum) ON UPDATE RESTRICT ON DELETE CASCADE
) ENGINE=INNODB;
Taking the idea a step further (for those of us still stuck with a legacy version of MySQL) you can have BOTH a protected & defaulted create_stamp AND an auto-updating update_stamp as follows:
If you have a table such as
CREATE TABLE `csv_status` (
`id` int(11) NOT NULL primary key AUTO_INCREMENT,
`create_stamp` datetime not null,
`update_stamp` timestamp default current_timestamp on update current_timestamp,
`status` enum('happy','sad') not null default 'happy'
);
Then you can define these triggers on it
drop trigger if exists set_create_stamp ;
create definer = CURRENT_USER trigger set_create_stamp BEFORE INSERT on
csv_status for each row
set NEW.create_stamp = now();
drop trigger if exists protect_create_stamp ;
delimiter //
create definer = CURRENT_USER trigger protect_create_stamp BEFORE UPDATE on
csv_status for each row
begin
if NEW.create_stamp != OLD.create_stamp then
set NEW.create_stamp = OLD.create_stamp;
end if;
end;//
delimiter ;
I have an issue with a trigger on a mysql database. I have a table such as follows:
id int not null auto_increment (PK)
parent_id int not null,
rank int not null
What I'm trying to do is use a trigger to update the rank to the next highest +10 when they have the same parent_id, but this doesn't seem to be working.
DELIMITER $$
DROP TRIGGER IF EXISTS after_insert $$
create trigger after_insert
after insert on mytable
FOR EACH row
BEGIN
IF EXISTS (SELECT rank FROM mytable WHERE parent_id = new.parent_id AND id != new.id ORDER BY rank DESC LIMIT 1) THEN
UPDATE mytable SET rank = 10
WHERE id = new.id;
ELSE
UPDATE mytable SET rank = 20
WHERE id = new.id;
END IF;
END
$$
I've tried setting the new rank to a variable and calling the update statement using that, and again it didn't work. I even created another table to log what values were being selected and that worked perfectly so I can't quite understand what's going on. Is it a case of, although the trigger is "AFTER INSERT" the insert hasn't actually happened so it can't update the row it's just inserted? Another reason I ask this is, I've even tried updating the rank to different values e.g 1 and 2 depending on which statement it goes to, but it always ends up being 0.
I think you're on the right track with this thought:
Is it a case of, although the trigger is "AFTER INSERT" the insert hasn't actually happened so it can't update the row it's just inserted?
From the FAQ:
B.5.9: Can triggers access tables?
A trigger can access both old and new data in its own table. A trigger can also affect other tables, but it is not permitted to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger.
The documentation isn't clear that what you're doing won't work. OTOH, the documentation isn't clear that what you're trying to do will work either.
I think you'd be better off using a BEFORE INSERT trigger and setting NEW.rank in there. Then, the new row would have the right rank value when it is actually inserted into the table rather than patching it after. Also, you'd be able to simplify your existence check to just this:
EXISTS(SELECT rank FROM mytable WHERE parent_id = new.parent_id)
as NEW.id wouldn't have a useful value and the new row wouldn't be in the table anyway; the ORDER BY and LIMIT are also unnecessary as you're just checking if something exists so I took them out.
A BEFORE INSERT trigger seems to match your intent better anyway and that will give you correct data as soon as it is inserted into your table.
If you want the rank to be set +10 more than highest "brother's" rank, you could use:
DELIMITER $$
DROP TRIGGER IF EXISTS whatever $$
create trigger whatever
BEFORE INSERT ON mytable
FOR EACH row
BEGIN
SET NEW.rank = 10 + COALESCE(
( SELECT max(rank)
FROM mytable
WHERE parent_id = NEW.parent_id
), 0 ) ;
END
$$