MySQL Trigger on update - mysql

I have a database with 2 tables. One tables contains data regarding references (job refs) the other contains votes. In order to get to the vote stage, you need 5 references. In another database, i must change a group_id once they have 5 refs.
I was trying to use something like below:
CREATE TRIGGER update_group AFTER UPDATE ON refs
FOR EACH ROW
BEGIN
IF (SELECT recruit_id from refs where count(refs) = 5) THEN
UPDATE users.members
SET group_id=10
WHERE member_id=recruit_id;
END;
Is something like this even feasible? if this doesn't work, my fallback is to use a bash script in a cron job that runs every 5 minutes, but a trigger just seems so much more efficient (and instantaneous)

You may use NEW. to refer respectively affected recruit_id after change, do a count and update the foreign table accordingly.
CREATE TRIGGER update_group AFTER UPDATE ON refs
FOR EACH ROW
BEGIN
SELECT #refs_no := count(*) from refs where recruit_id = NEW.recruit_id
IF (#refs_no = 5) THEN
UPDATE users.members
SET group_id=10
WHERE member_id=NEW.recruit_id;
END;

Related

Trigger Preventing Record Insertion

I was trying to create trigger which can update value of column user_count of table user_details using value of u_count of table user_info.
CREATE TRIGGER `test`
AFTER INSERT ON `user_details` FOR EACH ROW
BEGIN
DECLARE default_user_count int(11);
SELECT u_count INTO #default_user_count FROM
user_info WHERE user_info.id= user_details.id_c;
IF user_details.user_count= 0
THEN UPDATE user_details SET
user_count = default_user_count
WHERE user_details.id_c = user_info.id;
END IF;
END
Trigger saved successfully but when i tried to insert value in both table it is preventing to insert record into user_details means no row inserted in 2 this table, if we delete trigger then its working.
Can anyone let me know wrong with this trigger?
THanks,
M.
It's not really clear what you're trying to accomplish, but it seems like it's something like what we have below.
There are numerous errors in and ambiguities in your trigger.
Confusion on variables -- DECLARE default_user_count INT(11); does not declare the user-defined variable #default_user_count. It declares the program variable default_user_count. The # prefix references an entirely different variable scope and namespace.
SELECT and UPDATE from the table which invoked the trigger doesn't usually make sense (SELECT) or is completely invalid (UPDATE).
With in a trigger, you are operating FOR EACH ROW -- that is, for each row included in the statement that invoked the trigger. Inside an INSERT trigger, the NEW values for the row are in a pseudo-table/pseudo-row accessible via the alias NEW. For UPDATE triggers, there are NEW and OLD row values, and for DELETE triggers, just OLD.
AFTER INSERT doesn't seem to make sense. I think you're looking for BEFORE INSERT -- that is, while processing an INSERT INTO ... query, before the newly-inserted row actually gets written into the table, modify its values accordingly. The resulting row contains the original values except where the trigger has modified them.
SELECT ... INTO a variable is a practice you should not get into the habit of, because it can bite you in a way a scalar subquery can't, by leaving a variable unexpectedly unaltered instead of setting it to NULL as would be expected. In this case, it would have made no difference, but it's still a caution worth mentioning... and in this case, I've eliminated that intermediate variable altogether, so the subquery is the only option.
If you are trying to set a value in this table using a value found in another table, all you need to do is SET NEW.column_name equal to the value you want used in the row instead of the value provided with the insert statement.
CREATE TRIGGER `test`
BEFORE INSERT ON `user_details` FOR EACH ROW
BEGIN
IF NEW.user_count = 0 /* maybe also >> */ OR NEW.user_count IS NULL /* << this */ THEN
SET NEW.user_count = (SELECT ui.u_count
FROM user_info ui
WHERE ui.id = NEW.id_c);
END IF;
END
Again, it's unclear how the two tables are connected based on the content of the original question, but this appears to do what you're trying to accomplish.

How to put multiple updates in a trigger?

I hope you can help me here.
I am using MySQL + PhpMyAdmin and I have 2 tables in this problem.
Table 1: Accounts - id, account_name, website, etc. etc...
Table 2: Domains - id, domain_name, account_name
and I Inserted these queries into 2 triggers.
Before Update
update domains, accounts
set domains.account_name = NULL
where accounts.website != domains.domain_name
After Update
update domains, accounts
set domains.account_name = accounts.account_name
where domains.domain_name = main_accounts.website
With these, when I update something in the accounts table, it will automatically remove the account_name from domains table and put new account_name if a certain account is updated.
Images below will show example.
Tables not yet updated:
----------
Accounts Table
Domains Table
----------
----------
Updated View.
----------
----------
Accounts Table
Domains Table
So, on the second account table image, I have changed the domain and automatically, the domains table has been updated. I would want to make only 1 trigger that will contain those 2 update queries. I don't know if it's possible because after I complete this, I may also need to know how to update multiple different tables from 1 trigger. The reason why I ask is because I need to assign the account name for each sub-tables that are in use. Example, the main table is the accounts table and the sub tables that needs to be updated are:
domains.account_name
ip_address.account_name
phones.account_name
payments.account_name
So, I don't know if it's even possible to update those sub-tables under column "account_name" when the main table "accounts" is updated.
Thank you. I hope my question is clear. :D :D
You can group multiple statements into a trigger with BEGIN and END.
Example:
DELIMITER $$
CREATE TRIGGER my_trigger BEFORE INSERT ON accounts
FOR EACH ROW
BEGIN
-- Statement one
UPDATE domains
SET domains.account_name = accounts.account_name
WHERE domains.domain_name = main_accounts.website;
-- Statement two
UPDATE another_table
SET another_table.column_name = accounts.account_name
WHERE another_table.domain_name = accounts.some_column;
-- More UPDATE statements
END$$

insert ... select ... on duplicate key update + delete obsolete rows

I need to update a table with pre-calculated values from tables where data can be added/updated/deleted.
I could use
insert into precalculated(...)
select ... from ...
on duplicate key update ...
to add/update the pre-calculated table but is there an optimized method to delete the obsolete rows ?
I think you should create a stored procedure that deletes the data of your related tables if and only if the records fulfill a condition.
There's not enough information in your question to design the procedure, but I can give you a little example:
delimiter $$
create procedure delete_orphans()
begin
declare id_orphan int;
declare done int default false;
declare cur_orphans cursor for
select distinct d.id
from data as d
left join precalculated as p on d.id = p.id
where p.id is null;
declare continue handler for not found set done = true;
open cur_orphans;
loop_delete_orphans: loop
fetch cur_orphans into id_orphan;
if done then
leave cur_orphans;
end if;
delete from data where id = id_orphan;
end loop;
close cur_orphans;
end$$
delimiter ;
This procedure will delete every row in the data table that does not have at least one related row in the precalculated table.
Of course, this approach might be inneficient, because it will delete the rows one by one, but as I said this is only an example. You can customize it to fit your needs.
You can call this procedure from a trigger if you want (with call delete_orphans()).
Hope this helps.
Since you are always adding or updating rows that exist in these other tables, and you want to remove any rows that don't exist, why don't you just :
DELETE FROM precalculated
insert into precalculated(...)
select ... from ...
on duplicate key update ...
Always starting clean means you don't have to worry about orphans later.
You could add triggers for insert, delete and update on the main tables that maintains precalculated.
When inserting or updating the same code can be used to calculate the values and issuing a replace into precalculated (...) values (...)
When deleting it's probably the same, with the addition that you'll also delete rows from precalculated that are orphans. Be smart here and use values from the original delete to query precalculated for orphans instead of doing a table scan.
I may have found my solution using rename.
so basically, I will do a simple insert select to the temporary table and then
rename precalculated to precalculated_temprename, precalculated_temp to precalculated, precalculated_temprename to precalculated_temp;
truncate precalculated_temp;
need some tests but it seems the rename operation is fast and atomic.

Multiple MySQL queries (no PHP)

I am wondering if it is possible to perform a SQL query then update another table with the generated ID and continue through all of the rows?
I have this SQL query that works but what I need to do is after each row is added to cards to then update merged.cars_id with the last generated ID so they are linked. normally I would do this with PHP but ideally I would like to just do it with MySQL if possible.
MAIN QUERY
INSERT INTO cards (first_contact_date, card_type, property_id, user_id)
SELECT first_contact_date, 'P', property_id, user_id FROM merged
THEN I NEED WITH MATCHING ROWS (Roughly)
UPDATE merged SET merged.card_id = LAST_INSERT_ID (FROM ABOVE) into the matching record..
Is something like this possible and how do I do it?
I would recommend using MySQL triggers to do this
http://dev.mysql.com/doc/refman/5.0/en/create-trigger.html
A trigger is a function that will be executed AFTER or BEFORE the INSERT or DELETE or UPDATE is done over any record of your table.
In your case you need to do a AFTER INSERT on cards that just updates the merged table. Make sure its AFTER insert as you wont be able to access the new row's ID otherwise.
The code would look something like this, assuming the id field from the cards table its named "id"
delimiter |
CREATE TRIGGER updating_merged AFTER INSERT ON cards
FOR EACH ROW BEGIN
UPDATE merged SET card_id = NEW.id;
END;
|
delimiter ;
May I suggest Stored Procedures?
http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html
--EDIT--
Ah yes, triggers. For this particular situation, Jimmy has the answer. I will leave this post for the sake of the link.
I would set up a trigger to do this. For mysql, read http://dev.mysql.com/doc/refman/5.0/en/triggers.html. This is what triggers are designed to handle.

MYSQL auto increase column entity by 1 on update?

I have a table: ID,name,count,varchar(255)
Now, what i'd like is to increase the "count" each time that row in the table is updated.
Of course, the easy way is to read first, get the value, increase by 1 in php, then update with the new value. BUT!
is there any quicker way to do it? is there a system in mysql that can do the ++ automatically? like autoincrement, but for a single entity on itself?
I see two options:
1.
Just add this logic to every update query
UPDATE `table` SET
`data` = 'new_data',
`update_counter` = `update_counter` + 1
WHERE `id` = 123
2.
Create a trigger that will do the work automatically:
CREATE TRIGGER trigger_name
AFTER UPDATE
ON `table`
FOR EACH ROW
BEGIN
UPDATE `table`
SET `update_counter` = `update_counter` + 1
WHERE `id` = NEW.id
END
Create a trigger:
http://dev.mysql.com/doc/refman/5.1/en/create-trigger.html
Triggers are pieces of code that are "triggered" by the database on certain events. In your case, the event would be an update. Many RDBMS support triggers, so does MySQL. The advantage of using a trigger is that every piece of your PHP logic that updates this entity, will implicitly invoke the trigger logic, you don't have to remember that anymore, when you want to update your entity from a different piece of PHP logic.
you can look up at the trigger
or can do with the extra mysql query
update table set count=count+1 ;
UPDATE table SET name='new value', count=count+1 WHERE id=...
An SQL update can use fields in the record being updated as a source of data for the update itself.