I am trying to replicate the Username field in my database. Specifically I was looking to add/remove the Username across different tables, whenever the row that contains Username is added inside UserDatabase. To that end, I was thinking of using the trigger mechanism.
I am thinking along the lines of:
CREATE TRIGGER 'addUsername' AFTER INSERT ON UserDatabase FOR EACH ROW
IF (UPDATE(Username))
BEGIN
INSERT INTO anothertable (Username) VALUES ('NewUser');
END
My question is that is how do I capture the updated Username from UserDatabase and replicate it into NewUser? And also, is there a way to remove FOR EACH ROW as I only want the loop to run once?
Thanks!
From the manual:
Within the trigger body, you can refer to columns in the subject table (the table associated with the trigger) by using the aliases OLD and NEW. OLD.col_name refers to a column of an existing row before it is updated or deleted. NEW.col_name refers to the column of a new row to be inserted or an existing row after it is updated.
And no, you can not remove for each row and I think you misunderstood it a little. There actually is no loop. for each row refers to multiple rows in your insert or update statement. When you add multiple users with one insert statement, you want all of them replicated, right? Not just one.
Then you should note, that there's a difference between single-quotes and backticks. Backticks should be used, if a column or tablename or whatever includes characters that shouldn't be there, like a space, or if the name is actually a reserved keyword. Single-quotes, like you used them for the trigger name are used to tell MySQL it's a string.
Your trigger should look something like this:
CREATE TRIGGER 'addUsername' AFTER INSERT ON UserDatabase
FOR EACH ROW
INSERT INTO anothertable (Username) VALUES (NEW.Username);
For an update statement, you have to create another trigger.
Related
I'm using a trigger that triggers AFTER INSERT, when the user inserts data into the the table i want to be able to use the information that was just inserted into the table in my trigger.
Is there any way to do this?
Use the special variable new to get the data for the new added row(s), as described in the manual at 13.1.22 CREATE TRIGGER Statement
Within the trigger body, you can refer to columns in the subject table (the table associated with the trigger) by using the aliases OLD and NEW. OLD.col_name refers to a column of an existing row before it is updated or deleted. NEW.col_name refers to the column of a new row to be inserted or an existing row after it is updated.
I have a table on a mysql 5.7 db, containing say athletes with their mean, max, avg times in a specific sport. I have another table that lists some calculated statistics based on those values.
I managed to do the calculcations that end up on the second using stored procedures. I use as input parameter to the stored procedure the athlete's name.
So when in the first table, an athlete is inserted (with his/her avg/min/max times) or his/her values are updated and I run the stored procedure, the later updates the statistics table.
My question is how to achieve the same result with triggers?
I guess it is feasible/easy to update the entire table on each insert or update of the first table. What would be more efficient performance-wise, would be on each :
INSERT into table1 values (..) where athlete_name="John Do"
(...)
ON DUPLICATE KEY UPDATE (...)
Run a trigger in the pseudocode form :
INSERT into statistics_table values (..) where athlete_name="John Do"
ON DUPLICATE KEY UPDATE (...)
How can the the athlete_name="John Do" be passed to the trigger dynamically, to avoid update the entire statistics table?
You cannot pass any parameters to a trigger and the insert statement does not support the where clause either.
Having said this, a trigger can pick up the user's name from the record being inserted / updated / deleted using NEW.athlete_name or OLD.athlete_name (whichever is required) and use that to call a stored procedure:
Within the trigger body, the OLD and NEW keywords enable you to access
columns in the rows affected by a trigger. OLD and NEW are MySQL
extensions to triggers; they are not case-sensitive.
In an INSERT trigger, only NEW.col_name can be used; there is no old
row. In a DELETE trigger, only OLD.col_name can be used; there is no
new row. In an UPDATE trigger, you can use OLD.col_name to refer to
the columns of a row before it is updated and NEW.col_name to refer to
the columns of the row after it is updated.
A column named with OLD is read only. You can refer to it (if you have
the SELECT privilege), but not modify it. You can refer to a column
named with NEW if you have the SELECT privilege for it. In a BEFORE
trigger, you can also change its value with SET NEW.col_name = value
if you have the UPDATE privilege for it. This means you can use a
trigger to modify the values to be inserted into a new row or used to
update a row. (Such a SET statement has no effect in an AFTER trigger
because the row change will have already occurred.)
You can create triggers that fire after each insert or update on the parent table (athletes). Within each trigger, you can access the value of column athlete_name on the record that was just created or changed, and then invoke your stored procedure using CALL().
Here is a code sample for such an INSERT trigger :
CREATE TRIGGER athletes_upd AFTER INSERT ON athletes
FOR EACH ROW
BEGIN
CALL my_procedure(NEW.athlete_name);
END;
UPDATE trigger :
CREATE TRIGGER athletes_upd AFTER UPDATE ON athletes
FOR EACH ROW
BEGIN
CALL my_procedure(NEW.athlete_name); -- or maybe OLD.athlete_name ?
END;
When I insert data in db I have to compare the current record with the previous one. If neccassary, some values of the current record needs to be modified.
I've tried some pieces of SQL like below, but all give SQL errors. This one gives me an error says that I select more than 1 records.
DELIMITER $$
CREATE
TRIGGER set_moment_display
BEFORE INSERT ON data
FOR EACH ROW
BEGIN
DECLARE moment DATETIME;
SELECT press_moment_1 INTO moment FROM data LIMIT 1;
IF moment > NEW.press_moment_1 THEN SET NEW.press_moment_1 = moment;
END IF;
END$$
DELIMITER ;
How do I achieve what I've described above.
The problem here is that, since a SQL database has no implicit concept of row ordering (you supply the ordering criteria on every query), there is no "previous" row for the trigger to look at. The "previously inserted row" has no meaning in the context of an insert trigger.
Suppose for a moment that it did and there were several processes inserting rows in the table. When the trigger fired for process #1's insert, which row is the "previous" row? The one previously inserted by process #1? Suppose the chronologically "most recent" row was actually inserted by process #3?
If you need to do this it cannot be done in a trigger unless you can use a know key value to identify the row you understand as "most recent". Otherwise it must be handled in the application that is doing the inserts.
You can use the alias "OLD."
You can refer to columns in the subject table
(the table associated with the trigger) by using the aliases OLD and NEW.
OLD.col_name refers to a column of an existing row before
it is updated or deleted. NEW.col_name refers to the column
of a new row to be inserted or an existing row after it is updated
UPDATE
Jim Garrison properly pointed up to me the mistake, "BEFORE INSERT" doesn't have "OLD." values, this alias works only for UPDATE and DELETE.
hi i have two tables namely
sms(Message,sms_index...columns)
c_paid_bribe(c_addi_info,....)
what i want to do is to insert the values of Message column of sms table into c_addi_info column of c_paid_bribe table automatically whenever a new value is inserted into sms table.
I tried this
$query=mysql_query("insert into bd_paid_bribe(c_addi_info) select Message from sms");
But when a new value is inserted and i run the .php file the already existed values are also inserting into the table again.....
Q: what i want to do is to insert the values of Message column of sms table into c_addi_info column of c_paid_bribe table automatically whenever a new value is inserted into sms table.
A: If you want to update one table when another is changed (and, for whatever reason, you can't simply do this in your application), then use "triggers":
http://net.tutsplus.com/tutorials/databases/introduction-to-mysql-triggers/
Q: But when a new value is inserted and i run the .php file the already existed values are also inserting into the table again.....
A: You want an "upsert". For example:
How do I update if exists, insert if not (AKA "upsert" or "merge") in MySQL?
What you want to do is simply to make two queries that are comitted in one transaction. This is what transactions are for. See here for examples on how to do it:
PHP + MySQL transactions examples
I've got a number of tables that "share" a single auto-incrementing primary key - this is accomplished via a trigger on insert which looks like this:
FOR EACH ROW
BEGIN
INSERT INTO master (time) VALUES (NOW());
SET NEW.id = LAST_INSERT_ID();
END
This produces the PK for the just inserted row. This does, however, create the problem that I can't seem to figure out what that ID was. last_insert_id obviously returns nothing as the above statement wasn't executed on what's considered "the current connection".
Is there a way to access the most recently inserted row on a connection without an auto-incrementing primary key?
Update: As a temporary(?) measure I've removed the trigger and now generate the ID by making the insert to master within my model. Just seems like it would be nicer if I could somehow return the value that the trigger set.
The doc does say, "For stored functions and triggers that change the [LAST_INSERT_ID] value, the value is restored when the function or trigger ends, so following statements do not see a changed value."
Try a stored procedure, which can do your two INSERTS and return the assigned ID.
Or, give up on doing things the "Oracle way", drink the MySql Kool-Aid, and just use an auto-incrementing id on the table.