I recentely posted a question about a trigger able to prevent update of specific tables, then I asked in comments a solution to prevent update of speficic columns and rows. I managed to write a trigger that prevents update of specific columns, but i still cant figure how to limit this to a specific number of rows. So I thought I should open a new question in order to give this solution to the ones that need it and also to have a reply on my other problem, meaning limit this trigger to a specific # of rows. The following trigger works for columns:
DELIMITER ;;
CREATE TRIGGER my_trigger BEFORE UPDATE ON test_table FOR EACH ROW
IF (NEW.price != OLD.price OR NEW.name != OLD.name) THEN
UPDATE UPDATE_OF_TABLE1_IS_NOT_ALLOWED SET value='Update not allowed!';
END IF;;
DELIMITER ;
Is there any way to choose the # of rows hit by this trigger? lets say i want to select an interval of rows or specific rows numbers... any hint? thanks a lot.
Related
Having a table with the name transitions, I want to change the values of all the rows after any update is made.
I'm using the following trigger, which changes only the ROW that I'm making the update to.
CREATE TRIGGER signaturetrigger BEFORE UPDATE ON `transactions` FOR EACH ROW
BEGIN
SET New.signature = '288';
END
I'm trying to change all the rows to signature = 288, how can I modify the trigger in order to archieve that? I thought that using FOR EACH ROW would be enough.
Thanks in advance.
You can use an after update trigger with an update statement:
CREATE TRIGGER signaturetrigger AFTER UPDATE ON `transactions`
FOR EACH ROW
BEGIN
UPDATE transactions
SET New.signature = '288';
END;
This does seem like a very strange thing to do, however.
Consider an alternative: just add an UpdatedAt column into the table and update the signature in that row. Then, when you want the most recent signature use:
select signature
from transactions
order by UpdatedAt desc
limit 1;
An index on transactions(UpdatedAt, signature) will make this quite speedy. And, the update will go much, much faster than updating all rows.
I'm fairly new to triggers and have already tried searching for a solution to my question with little results. I want to update a single row's start time column whenever it's active column is set to 1.
I have two columns ACTIVE (number) and START_TIME (timestamp) in my_table. I would like to create a PL/SQL trigger that updates the START_TIME column to current_timestamp whenever an update statement has been applied to the ACTIVE column - setting it to 1.
So far I have only seen examples for inserting new rows or updating entire tables which isn't what I'm looking to do. I'd have thought there would be a fairly simple solution to my problem.
This is what I've got so far from other examples. I know the structure of my solution is poor and I'm asking for any input to modify my trigger to achieve my desired result.
CREATE OR REPLACE TRIGGER routine_active
AFTER UPDATE ON my_table
FOR EACH ROW
WHEN (my_table.ACTIVE = 1)
begin
insert my_table.start_time = current_timestamp;
end;
\
you can use like this .it may help you
write the update query instead of insert query
CREATE OR REPLACE TRIGGER routine_active
AFTER UPDATE ON my_table
FOR EACH ROW
WHEN (new.ACTIVE = 1)
begin
update my_table set start_time =current_timestamp;
end;
I think it should be a BEFORE UPDATE, not AFTER UPDATE, so it saves both changes with a single action. Then you don't need the INSERT or UPDATE statements. I also added the "OF active" clause, so it will only start this trigger if that column was updated, which may reduce the workload if other columns get updated.
CREATE OR REPLACE TRIGGER routine_active
BEFORE UPDATE OF active ON my_table
FOR EACH ROW
BEGIN
IF active = 1
THEN
:NEW.start_time = current_timestamp;
END IF;
END;
I want to UPDATE my row after it has been updated by the user.
Example if after the user selects 32, and Principal previously entered is > 1000. Then Update the 32 to 40.
CREATE TRIGGER updateusers_id AFTER UPDATE ON Table
FOR EACH ROW
BEGIN
IF(NEW.users_id = 32 AND Table.Principal > 50000) THEN
UPDATE loans SET users_id = 40;
END IF;
END
Think about it for a second and you'll realize the first problem: if what you actually need here is an AFTER update trigger... then what would a BEFORE update trigger do?
AFTER UPDATE means after the update query has already changed the row data. What you are actually looking to is BEFORE UPDATE -- you want to hijack the update in mid-stream, before the table data actually gets changed, and potentially modify the values that will actually be written to the database.
UPDATE loans SET users_id = 40;
There are two problems with this. First, you know what an UPDATE without WHERE does... right? It updates all the rows in the table. Luckily, the server didn't let you do that. But the solution is not to add a WHERE clause -- it's this:
IF(NEW.users_id = 32 AND NEW.Principal > 50000) THEN
SET NEW.users_id = 40;
END IF;
The NEW pseudotable contains the row data that the user has tried to cause the UPDATE (that fired the trigger) to write to the row. You are in a BEFORE UPDATE ... FOR EACH ROW trigger, so setting NEW values overrides anything the user tried to do... which appears to be what you are wanting to accomplish.
I'm trying to create a trigger that will automatically increase the year column by 1 when the month column is 12, and then empty the month column.
But I don't understand triggers that well and I'm confusing myself in my attempts, so I was hoping someone could look over this code to see if it would work or suggest improvements:
CREATE TRIGGER aging BEFORE UPDATE ON dogs
FOR EACH ROW
DELETE FROM dogs WHERE month = 12;
UPDATE year SET year = year+1;
Thanks!
Two things to point out...
First, a trigger is clearly the wrong choice for what you want to do. Not only because the trigger can be avoided by calculating the age on the fly based on birth of date. But also, because a trigger only affects the rows that are affected by the corresponding statement. Don't be fooled by the FOR EACH ROW. You write something like
UPDATE table SET whatever = whatever WHERE month = 12;
and all the rows where month = 12 is true are affected. What you seem to want to do, is to update the whole table to check if in some rows your condition is true. Not only is this a performance nightmare, you are also restricted to one trigger (per event) per table. Meaning you can have i.e. one BEFORE UPDATE and 1 AFTER UPDATE but not 2 BEFORE UPDATE.
The second thing to note is, that you can't issue an UPDATE statement in an UPDATE trigger. This would cause an infinite loop :)
Instead you use the aliases NEW and OLD. NEW refers to the value of a column given by the UPDATE statement and OLD refers to the value of the column before the UPDATE statement was executed.
In your case (althoug it's hopefully clear by now, that you shouldn't use the trigger in this case), one would write the trigger like this:
Given this initial statement
UPDATE myTable SET whatever = whatever;
which updates the whole table, this trigger
DROP TRIGGER IF EXISTS [whatever you call this thing];
DELIMITER ##
CREATE TRIGGER aging BEFORE UPDATE ON dogs
FOR EACH ROW
IF (month = 12) THEN /*month refers to the column here, not a variable like in Gordon's answer*/
SET NEW.year = OLD.year+1;
SET NEW.month = 1;
END IF;
END ##
would update the columns correctly.
I've never created a trigger before, but I just read through the docs. This is my attempt...
DELIMITER ||
DROP TRIGGER ID EXISTS [whatever you call this thing]
||
DELIMITER ##
CREATE TRIGGER aging BEFORE UPDATE ON dogs
FOR EACH ROW
DECLARE month integer;
IF (month = 12) THEN
-- DELETE FROM dogs WHERE month = 12;
-- this will delete the record; probably not what you want
UPDATE year SET year = year+1;
UPDATE month SET month = NULL;
END IF;
END;
##
so i've edited my code
i had this problem in another trigger but this time even changing WHERE clause doesn't help
DELIMITER $$
CREATE TRIGGER pic_album_change AFTER UPDATE ON pictures
FOR EACH ROW BEGIN
UPDATE albums SET counter = counter + 1 WHERE albums.id = NEW.album_id;
UPDATE albums SET counter = counter - 1 WHERE albums.id = OLD.album_id;
END $$
DELIMITER ;
error :
<p>Error Number: 1442</p><p>Can't update table 'pictures' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
i dont see any changes on the pictures table in this trigger
i have another trigger that involves these two tables
DELIMITER $$
CREATE TRIGGER album_change
AFTER UPDATE
ON albums
FOR EACH ROW
BEGIN
UPDATE pictures
SET
level = NEW.level
WHERE
pictures.album_id = NEW.id ;
END $$
DELIMITER ;
Your WHERE clause is the wrong way round.
WHERE albums.id = NEW.album_id
would cause albums.counter to be incremented (presumably that's the number of pictures in each album).
It matters because joins on tables are not commutative — the direction of the join is important. Here you need to find the record in albums to update based on the value of the row in pictures.
While in this case there isn't really any ambiguity, SQL needs to follow rules about joins.
The issue with your second trigger is that MySQL is preventing a continuous cycle of updates. You have a trigger pic_album_change which updates albums when pictures is updated. And you have a trigger album_change which updates pictures when albums is updated. Those triggers will trigger each other.
It seems to me that the database design may need to be changed. Do you really need albums.counter when that data can be found with SELECT count(*) FROM pictures WHERE album_id=...? It should be possible to normalise data so that there no circular references in triggers. In fact triggers may not be necessary at all.