I need a bit of help with creating a trigger in mysql:
I have a column named “country” and another one named “tag”.
Everytime when someone insert in the city “Los Angeles” for example, I want that my trigger to insert in “tag” column the text “is from California”.
Edit:
delimiter //
CREATE TRIGGER update_tag AFTER UPDATE ON users
FOR EACH ROW
BEGIN
IF (city = 'Los Angeles') THEN
INSERT INTO users(tag) VALUES (California);
END IF;
END;//
delimiter ;
That seems to be executed with no errors, but is not inserting anything in "tag" column,
Any ideea why?
PS. I would appreciate from the ones that rated this post with "-" to write me a PM and tell me what I did wrong :). Thank you.
You cannot use an insert statement to update the row you are currently processing. You should use the SET NEW.cxy = "" syntax.
I have prepared a working sqlfiddle for you, which hopefully shows want you wanted to achieve.
CREATE TABLE users (
id int auto_increment PRIMARY KEY,
`city` varchar(255),
`tag` varchar(255)
)//
CREATE TRIGGER update_tag BEFORE UPDATE ON users
FOR EACH ROW
BEGIN
IF (NEW.city = 'Los Angeles') THEN
SET NEW.tag = "California";
END IF;
END//
INSERT INTO users VALUES (1, 'test', '')//
UPDATE users SET `city` = 'Los Angeles'//
Please notice that this is also a BEFORE UPDATE trigger, so that your changes are saved as well.
If one issues a SELECT * FROM users one receives a single row with
1 Los Angeles California
There is also a page in the MySQL manual containing trigger examples. You should read that thoroughly.
Related
I can't seem to get one of the triggers im trying to make to work at the moment it looks like this (has been messed around with alot in an attempt to get it to work so probably doesn't make any sense now)
CREATE TRIGGER `insertproductebay` AFTER INSERT ON `product`
FOR EACH ROW INSERT INTO eBayLinked
(product_id,company_id,eBay_ID,ebay_token_id,ebay_username)
SELECT ebay_token_id,ebay_username
FROM
'company'
WHERE
'company_id' = 'company_id'
VALUES
(NEW.product_id,NEW.company_id,NEW.eBay_ID,ebay_token_id,ebay_username)
The following makes it past the 1065 error
Care must be taken to use back-ticks around table and column names, and not to use single quotes there.
drop trigger if exists `insertproductebay`;
DELIMITER $$
CREATE TRIGGER `insertproductebay` AFTER INSERT ON `product`
FOR EACH ROW
INSERT INTO eBayLinked
(product_id,company_id,eBay_ID,ebay_token_id,ebay_username)
SELECT NEW.product_id,NEW.company_id,NEW.eBay_ID,ebay_token_id,ebay_username
FROM `company`
WHERE `company_id` = 'company_id'
$$
DELIMITER ;
The remaining problem as I see it could be what are you meaning by
WHERE `company_id` = 'company_id'
in a trigger. Because a trigger is a faceless piece of code that runs in the background, succeeding or failing silently. In other words, there is no user interface associated with it.
You can't mix the INSERT ... SELECT and INSERT ... VALUES syntaxes in that way. However, you can provide literal values in a select list, thusly:
CREATE TRIGGER insertproductebay AFTER INSERT ON product FOR EACH ROW
INSERT INTO eBayLinked
(product_id, company_id, eBay_ID, ebay_token_id, ebay_username)
SELECT NEW.product_id, NEW.company_id, NEW.eBay_ID, ebay_token_id, ebay_username
FROM company
WHERE company_id = NEW.company_id
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
Is it possible to set a column to its default value (or any specified value) on update when no value is specifically given in the statement? I was thinking that a trigger might accomplish this. Something like
IF ISNULL(NEW.column) THEN
NEW.column = value
END IF;
didn't work.
MySQL has function called DEFAULT(), which gets the default value from specified column.
UPDATE tbl SET col = DEFAULT(col);
MySQL Reference
UPDATE:
#JanTraenkner As far as I can tell, this is not possible. You can however make sure in your application code, that all columns are mentioned in your update statement and for those that do not have a value your use NULL as value. Then your trigger code is almost right, you just need to change it to
IF (NEW.column IS NULL) THEN
SET NEW.column = value
END IF;
Original answer:
I understood your question like, "set column to default value, if I don't specify the column in an update statement (which updates other columns from that table)".
To check with ISNULL() or col IS NULL doesn't work here, because when you don't specify it in the update statement it simply isn't there. There's nothing to check for.
I wrote this little example script which makes it work like I understood the question.
drop table if exists defvalue;
create table defvalue (id int auto_increment primary key, abc varchar(255) default 'default');
insert into defvalue (id) values (null);
insert into defvalue (id, abc) values (null, 'not_default_value');
insert into defvalue (id, abc) values (null, 'another_not_default_value');
drop trigger if exists t_defval;
delimiter $$
create trigger t_defval before update on defvalue
for each row
begin
set #my_def_value = (select default(abc) from defvalue limit 1);
if (new.abc = old.abc) then
set new.abc = #my_def_value;
end if;
end $$
delimiter ;
select * from defvalue;
update defvalue set id = 99 where id = 1;
select * from defvalue;
update defvalue set id = 98 where id = 2;
select * from defvalue;
I also had to save the default value of the column in a variable first because the function needs to know from which table. Unfortunately one can't specify that as parameter, not even as default(tablename.column).
All in all, please note, that this is rather a proof of concept. I'd recommend to solve this on application layer, not database layer. Having a trigger for this seems a bit dirty for me.
I have two tables. The first is my person table which has id, name, creation_date as values, I have a old_person table (id, name, modified_date) which I want to populate the value of person before it actually changes. How would I go about that? I have tried triggers but failed.
I tried as follows
create trigger Person_Trigger Update on person
before update
as
insert into old_person(id, name, modified)
select id, new.name, getdate()
from person
It's giving me syntax errors...Not many Trigger references out there either, a little push would be greatly appreciated!
Have a look at the following example
SQL Fiddle DEMO
IO hade a bit of trouble myself, but from How to Create Triggers in MySQL there was a line that made me think
The first MySQL command we’ll issue is a little unusual:
DELIMITER $$
Our trigger body requires a number of SQL commands separated by a
semi-colon (;). To create the full trigger code we must change
delimiter to something else — such as $$.
Finally, we set the delimiter back to a semi-colon:
DELIMITER ;
So in the SQL Fiddle I changed the query terminator to GO and that seemed top work.
CREATE TABLE person
(
id INT,
name varchar(20)
)
GO
CREATE TABLE old_person
(
id INT,
name varchar(20),
modified DATETIME
)
GO
CREATE TRIGGER Person_Trigger before update on person
FOR EACH ROW BEGIN
INSERT INTO old_person(id, name, modified)
VALUES (OLD.id, OLD.name, NOW());
END
GO
INSERT INTO person VALUES (1,'TADA')
GO
UPDATE person SET name = 'FOO'
GO
Try this:
DELIMITER \\
CREATE TRIGGER `Person_Trigger`
BEFORE UPDATE ON `Person`
FOR EACH ROW
BEGIN
DECLARE date_modified datetime;
SET date_modified = NOW();
INSERT INTO old_person(id, name, modified)
VALUES (OLD.id, OLD.name, date_modified);
END\\
This syntax works for me on my own projects. You may also need to declare delimiters before you begin the trigger. Also if you want to use the NEW keyword it should be AFTER update. Switch to the OLD keyword if you are going to keep using BEFORE update on your trigger.
I'm trying to create a trigger which sets selectoin allow to 1 when main state is updated to 3. However I can't get the query to work correctly. So far I have:
create table main
(main_id varchar(30) primary key,
name varchar(30) null,
state int null,
update_timestamp timestamp null);
create table selection
(id varchar(30) primary key,
allow varchar(30) null,
last_update_timestamp timestamp null);
//
create trigger upd_selectoin
before update on main
for each row
IF new.state = 3
THEN
UPDATE selection s
JOIN main m
ON m.main_id = s.id
SET s.allow = 1
WHERE s.id = NEW.main_id;
END IF;
END;
//
insert into main values (1,'row1',1,null);
insert into main values (2,'row2',0,null);
insert into selection values (1,null,null);
insert into selection values (2,null,null);
Error message:
Schema Creation Failed: 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 '//
You have at least two problems with the syntax:
You meant to use DELIMITER //
You forgot BEGIN
The correct definition might look like
DELIMITER //
CREATE TRIGGER upd_selectoin
BEFORE UPDATE ON main
FOR EACH ROW
BEGIN
IF NEW.state = 3 THEN
UPDATE selection s JOIN main m
ON m.main_id = s.id
SET s.allow = 1
WHERE s.id = NEW.main_id;
END IF;
END //
DELIMITER ;
Here is SQLFiddle demo
Now in your case
You probably want to use AFTER event instead of BEFORE to make sure that update in main has been made successfully before you make any updates to selection.
Also there is no point in JOINing selection with main since you already know main_id.
You can utilize INSERT ... ON DUPLICATE KEY UPDATE to make sure that a row in selection will exist even if it wasn't before
Looking at the selection schema you probably meant to assign a timestamp during that update
That being said a more succinct version of your trigger might look like
CREATE TRIGGER upd_selection
AFTER UPDATE ON main
FOR EACH ROW
INSERT INTO selection (id, allow, last_update_timestamp)
VALUES (NEW.main_id, IF(NEW.state = 3, 1, NULL), NOW())
ON DUPLICATE KEY UPDATE allow = VALUES(allow),
last_update_timestamp = VALUES(last_update_timestamp);
This version of a trigger doesn't even need DELIMITER and BEGIN ... END block because it contains only one statement.
Here is SQLFiddle demo