MySQL Trigger for Aging - mysql

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;
##

Related

PL SQL Trigger to update start time for row when a single column is updated

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;

MySql Stored Procedure how to approach?

Trying to get a trigger to work that refuses to I think it has to be setup as a procedure for it to work which I've never worked with before could anyone tell me how I would go about this? The trigger doesn't show errors when adding but just doesn't do anything
** It now does work apart from changing processed to 0)
UPDATE product
INNER JOIN ebaylinked ON ebaylinked.ebay_ID = product.eBay_ID
SET product.product_stock = product.product_stock - NEW.QuantitySold,NEW.Processed=0
WHERE product.eBay_ID = NEW.ebay_ID and NEW.Processed = 1
First of all, find a more descriptive name for your trigger ;).
Now for the actual problem, your references to the columns in ebaylinked in your trigger code are pretty much mostly wrong. To use the values in the record you just updated, you need to use the pseudorecord NEW, which is a single record containing the current row of the table as it will be after the update completes. References like ebaylinked.QuantitySold are ambiguous, as they do not specify which row of data is the correct one.
Also, you cannot refer to other rows in the triggering table. Your clauses SET ... ebaylinked.Processed=0 ... WHERE ... ebaylinked.Processed = 1 are thus both redundant and wrong, since the only row of ebaylinked your row trigger can see is the current one.
Your trigger code should thus be something like
CREATE TRIGGER `ebaylinked_update_product`
AFTER UPDATE ON `ebaylinked`
FOR EACH ROW
UPDATE product
SET product.product_stock = product.product_stock - NEW.QuantitySold
WHERE product.eBay_ID = NEW.ebay_ID;
Note I'm ignoring the processed column since it does nothing useful (provided the triggering insert is wrapped in a transaction), but if you absolutely must use it, you would change your trigger to before row as follows:
DELIMITER //
CREATE TRIGGER `ebaylinked_update_product`
BEFORE UPDATE ON `ebaylinked`
FOR EACH ROW
BEGIN
IF NEW.processed = 1 THEN
UPDATE product
SET product.product_stock = product.product_stock - NEW.QuantitySold
WHERE product.eBay_ID = NEW.ebay_ID;
SET NEW.processed = 0;
END IF;
END;
//
DELIMITER ;
Note the space between DELIMITER and whatever follows it. This directive is necessary in some clients when the trigger body contains multiple statements terminated by semicolons.
Hope that helps.
PS: You could do this with the trigger calling a stored procedure, but for something this simple I think it would add more complexity than it would be worth.
What is ebaylinked? You should be getting an error when you define the trigger.
If you want to update the table defined by the trigger, then you should use a BEFORE UPDATE trigger. So, I think you intend:
DELIMITER $$
CREATE TRIGGER `Update` BEFORE UPDATE ON `ebaylinked`
FOR EACH ROW
BEGIN
UPDATE product p
SET p.product_stock = p.product_stock - new.QuantitySold
WHERE p.eBay_ID = new.ebay_ID AND new.Processed = 1;
SET new.Processed = 0;
END; $$
DELIMTER ;

MYSQL AFTER Trigger UPDATE IF

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.

Trigger to prevent update of specific columns and rows in Mysql

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.

MySQL Trigger not getting triggered?

So this should be a fairly straight forward trigger, but my MySQL isn't great, so it's undoubtably a failure on my part.
It's not updating the stats table at all, even though it should be;
DROP TRIGGER countryUpdate;
DELIMITER //
CREATE TRIGGER countryUpdate AFTER INSERT ON stats
FOR EACH ROW BEGIN
DECLARE NewIP varchar(16);
DECLARE NewCountry varchar(80);
SET NewIP = inet_aton(new.vis_ip);
SET NewCountry = (SELECT country FROM iptocountry WHERE lower_bound <= NewIP AND upper_bound >= NewIP)
UPDATE stats
SET Country = NewCountry
END //
DELIMITER;
Well, first off, your UPDATE—if it works at all—is changing all rows in the stats table, and its doing that for each row inserted. That really doesn't make much sense. At minimum, you want to add a where clause to only hit the one row you've just inserted.
Apparently, though, that can't work at all in MySQL, because "a stored function or trigger cannot modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger." (Look under “Restrictions for Stored Functions”)
So, instead, you need to use a a before insert trigger, and do a SET new.country = NewCountry to fix the row up before its ever inserted.