I'm a newbie about SQL triggers. I'm trying to create a trigger when a row inserted to actions table, it should get the accounts table's matched account_id and update its value by adding to value.
Accounts table:
+------------------+---------------------+
| Variable_name | Value |
+------------------+---------------------+
| account_id | 1 |
| value | 100 |
+------------------+---------------------+
Inserted row to actions table:
+------------------+---------------------+
| Variable_name | Value |
+------------------+---------------------+
| account_id | 1 |
| value | 10 |
+------------------+---------------------+
I'm trying to make this situation: When inserted to actions with value 10, the row which has 1 account_id in the accounts table, it's value must be 110.
It would be simple update statement like so.
UPDATE accounts SET `value` = `value` + 10 WHERE account_id = 1
How we can do that using trigger. We will pick account_id and value from actions table using NEW keyword and use in this query.
DELIMITER $$
CREATE TRIGGER `actions_after_insert` AFTER INSERT ON `actions` FOR EACH ROW BEGIN
UPDATE accounts
SET `value` = `value` + NEW.`value`
WHERE account_id = NEW.account_id;
END
$$
Related
I have 2 tables which are below.
I would like to create a trigger for table_one. when changed the username in table_one, update user_id value from the table_two user value.
table_one:
+--------------+----------+
| user_id | username |
+--------------+----------+
| 15 | robin |
| 46 | albert |
+--------------+----------+
table_two:
+--------------+----------+
| id | user |
+--------------+----------+
| 1 | john |
| 2 | jack |
| 3 | robin |
| 4 | kylie |
| 5 | robert |
| 6 | albert |
| 7 | jay |
+--------------+----------+
thanks in advance
Do a BEFORE UPDATE trigger, not an AFTER UPDATE trigger.
(I don't think it's possible in an AFTER UPDATE trigger to modify the row that was updated, that fired the trigger. I could be wrong about that, but I just can't wrap my brain around how that would work.)
This is a demonstration of a BEFORE UPDATE trigger on table_one that assigns a value to the user_id column (of the row being updated) based on the result from a query:
DELIMITER $$
CREATE TRIGGER ...
BEFORE UPDATE ON table_one
BEGIN
# local variable we will temporarily store a value fetched from a query
DECLARE li_new_id BIGINT DEFAULT NULL; # match datatype of table_two.id
# lookup `id` value from `table_two` with a SQL query
SELECT s.id
INTO li_new_id
FROM table_two s
WHERE s.user = NEW.username
ORDER BY s.id
LIMIT 1 ;
# assign the value we fetched to the `user_id` column of the row being updated
SET NEW.user_id := li_new_id ;
END$$
DELIMITER ;
Note that if the query doesn't find a matching row, the local variable will have a NULL value. So the SET statement will assign NULL to to the user_id column. There's no check in the trigger that the value we assign won't violate a constraint (NOT NULL, UNIQUE, FOREIGN KEY).
Our project has a requirement that only one future dated record is allowed on a table. Every tables are maintaining record versions using start date and end date. A sample scenario is attached in below screenshot. (assume today's date is 7-Mar-2019)
So, how can I restrict database table to have more than one future dated record. Is there any constraints or triggers would help to do the validation from DB itself ?.( I am using MySQL db)
A simple way might be to overwrite end dates with null in a trigger for example
drop trigger if exists t;
delimiter $$
create trigger t before insert on t
for each row
begin
declare cnt int default 0;
select count(*) into cnt from t where end_date > date(now());
if cnt > 0 then
set new.end_date = null;
end if;
end $$
delimiter ;
insert into t (designation,end_date) values
('a','2019-03-07'),('a','2019-03-07'),('a','2019-04-07'),('a','2019-04-07'),
('b','2019-04-07');
select * from t;
+----+-------------+------------+
| id | designation | end_date |
+----+-------------+------------+
| 1 | a | 2019-03-07 |
| 2 | a | 2019-03-07 |
| 3 | a | 2019-04-07 |
| 4 | a | NULL |
| 5 | b | NULL |
+----+-------------+------------+
5 rows in set (0.00 sec)
You could tweak the code a bit by using an if exists test if you prefer.
SELECT time
FROM posts
ORDER BY time ASC;
This will order my posts for me in a list. I would like to reorder the table itself making sure that there are no missing table ids. Thus, if I delete column 2, I can reorder so that row 3 will become row 2.
How can I do this? Reorder a table by its date column so there is always an increment of 1, no non-existing rows.
Disclaimer: I don't really know why you would need to do it, but if you do, here is just one of many ways, fairly independent of the engine or the server version.
Setup:
CREATE TABLE t (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time` time DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
INSERT INTO t (`time`) VALUES ('13:00:00'),('08:00:00'),('02:00:00');
DELETE FROM t WHERE id = 2;
Initial condition:
SELECT * FROM t ORDER BY `time`;
+----+----------+
| id | time |
+----+----------+
| 3 | 02:00:00 |
| 1 | 13:00:00 |
+----+----------+
2 rows in set (0.00 sec)
Action:
CREATE TRIGGER tr AFTER UPDATE ON t FOR EACH ROW SET #id:=#id+1;
ALTER TABLE t ADD COLUMN new_id INT NOT NULL AFTER id;
SET #id=1;
UPDATE t SET new_id=#id ORDER BY time;
DROP TRIGGER tr;
Result:
SELECT * FROM t ORDER BY `time`;
+----+--------+----------+
| id | new_id | time |
+----+--------+----------+
| 3 | 1 | 02:00:00 |
| 1 | 2 | 13:00:00 |
+----+--------+----------+
2 rows in set (0.00 sec)
Cleanup:
Further you can do whatever is more suitable for your case (whatever is faster and less blocking, depending on other conditions). You can update the existing id column and then drop the extra one:
UPDATE t SET id=new_id;
ALTER TABLE t DROP new_id;
SELECT * FROM t ORDER BY `time`;
+----+----------+
| id | time |
+----+----------+
| 1 | 02:00:00 |
| 2 | 13:00:00 |
+----+----------+
2 rows in set (0.00 sec)
Or you can drop the existing id column and promote new_id to the primary key.
Comments:
A natural variation of the same approach would be to wrap it into a stored procedure. It's basically the same, but requires a bit more text. The benefit of it is that you could keep the procedure for the next time you need it.
Assuming you have a unique index on id, a temporary column new_id is needed in a general case, because if you start updating id directly, you can get a unique key violation. It shouldn't happen if your id is already ordered properly, and you are only removing gaps.
Assume the following structure:
Table1:
ID | name
Table2:
ID | name
Table3:
ID | table1_id | table2_id | value
I want to build a trigger, after insert to Table1 if id not exist, to create new rows for each row in Table2 inside Table3 with the corresponding IDs.
What I did so far is creating this logic in php, I have never created triggers this complex before so I don't really know how to approach this.
Example:
Customers Table after insert:
+----+------+
| ID | Name |
+----+------+
| 1 | Dan |
+----+------+
Currency Table:
+----+------+
| ID | Name |
+----+------+
| 1 | USD |
| 2 | EUR |
+----+------+
Customers Currency Table after trigger
+----+---------------+-------------+-------+
| ID | customer_id | currency_id | Value |
+----+---------------+-------------+-------+
| 1 | 1 | 1 | NULL |
| 2 | 1 | 2 | NULL |
+----+---------------+-------------+-------+
Another option that you can use is:
DELIMITER $$
DROP TRIGGER /*!50032 IF EXISTS */ `trg_bi`$$
CREATE TRIGGER `trg_bi` BEFORE INSERT ON `table1`
FOR EACH ROW
BEGIN
INSERT INTO `table3` (`table1_id`, `table2_id`)
SELECT NEW.`id`, `t2`.`id`
FROM `table2` `t2`
WHERE NOT EXISTS (SELECT NULL FROM `table1` `t1` WHERE `t1`.`id` = NEW.`id`);
END$$
DELIMITER ;
Here is validated by the id column table1, but you can use the column you want to validate, however, depends as validate that there is no 'customer' in table1.
SQL Fiddle example
To deal with this you need to use cursor in trigger, here is a nice tutorial on this http://www.mysqltutorial.org/mysql-cursor/
Now in your case I would suggest that the customer table id should be primary key auto incremented so that you always have unique value
So here how it should be
create table customer (id int primary key auto_increment , name varchar (100));
create table currency (id int primary key auto_increment, name varchar(100));
insert into currency (name) values ('USD'),('EUR') ;
create table customer_currency (id int primary key auto_increment, customer_id int , currency_id int , val varchar(100));
The trigger will be something as
delimiter //
create trigger customer_add after insert on customer
for each row
begin
DECLARE done INT DEFAULT FALSE;
DECLARE currency_id int;
DECLARE currency_val varchar(100);
DECLARE cur CURSOR FOR SELECT id,name FROM currency;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
ins_loop: LOOP
FETCH cur INTO currency_id,currency_val;
IF done THEN
LEAVE ins_loop;
END IF;
INSERT INTO customer_currency (customer_id,currency_id,val) VALUES (NEW.id,currency_id,currency_val);
END LOOP;
CLOSE cur;
end ; //
delimiter ;
Now in mysql lets add a record on customer table
mysql> insert into customer (name) values ('Abhik') ;
Query OK, 1 row affected (0.02 sec)
Now lets see what is there in the customer_currency symbol
mysql> select * from customer_currency ;
+----+-------------+-------------+------+
| id | customer_id | currency_id | val |
+----+-------------+-------------+------+
| 1 | 1 | 1 | USD |
| 2 | 1 | 2 | EUR |
+----+-------------+-------------+------+
In the trigger I am adding the currency value as well in the 3rd table if you do not want then can ignore that and it will become null.
You can write an after delete trigger on customer and delete the data from customer_currency where customer_id is the id of the deleted row in customer table.
I'm quite new to setting up tables in MySQL and there is something I'd like to do which is a bit more advance than I'm able to do.
I have two columns as part of a composite primary key, one is a Date and an ID I would like to be an auto increment integer. For each date, I would like to reset the auto integer to 0, so something like this:
|-----------------|
|Date | ID |
|-----------------|
|2012-06-18 | 1 |
|2012-06-18 | 2 |
|2012-06-18 | 3 |
|2012-06-19 | 1 |
|2012-06-19 | 2 |
|2012-06-20 | 1 |
|-----------------|
Thanks
Here this should work.
CREATE TABLE `answer`(
`dates` DATE NOT NULL,
`id` mediumint(9) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`dates`,`id`)
) ENGINE=MyISAM;
It is known to cause problems with innoDB. Hope this helps you.
EDIT: RESULTS
2012-06-19 1
2012-06-19 2
2012-06-19 3
2012-07-19 1
2012-07-19 2
2012-08-19 1
On php myadmin.
Well, for me mysql does what you want automatically.
mysql> CREATE TABLE TestData(Date date not null, ID int unsigned not null auto_increment, PRIMARY KEY(Date, ID));
mysql> INSERT INTO TestData SET Date = "2012-06-18";
mysql> INSERT INTO TestData SET Date = "2012-06-18";
mysql> INSERT INTO TestData SET Date = "2012-06-18";
mysql> INSERT INTO TestData SET Date = "2012-06-19";
mysql> INSERT INTO TestData SET Date = "2012-06-19";
mysql> INSERT INTO TestData SET Date = "2012-06-20";
mysql> select * from TestData;
+------------+----+
| Date | ID |
+------------+----+
| 2012-06-18 | 1 |
| 2012-06-18 | 2 |
| 2012-06-18 | 3 |
| 2012-06-19 | 1 |
| 2012-06-19 | 2 |
| 2012-06-20 | 1 |
+------------+----+
No magic involved.
You can create a before insert trigger.
DELIMITER $$
CREATE TRIGGER `composite_auto_increment` BEFORE INSERT ON `your_table`
FOR EACH ROW
BEGIN
DECLARE max_id INT(11); -- add the appropriate column length from your table definition
SELECT ID FROM `your_table` WHERE `Date` = DATE(NOW()) INTO max_id;
SET NEW.ID = IF(ISNULL(max_id), 1, max_id + 1);
END$$
This way, if and ID already existed for the day, it gets incremented. If it didn't, it gets set to 1. Note that in this scenario, ID isn't AUTO_INCREMENT in the table definition. It just gets done by the trigger.
In trigger:
SELECT ID FROM your_table WHERE Date = DATE(NOW()) INTO max_id;
must be:
SELECT max(ID) FROM your_table WHERE Date = NEW.key_field INTO max_id;
but better is lock by key.
this is better for concurrent inserts on innodb.