Trigger SQL update on insert - mysql

I need some help on creating a trigger on MySQL.
I have a table "comment":
id_comment | id_topic | comment
and the "topic" table:
id_topic | topic | comments_ammount
I need to increase comments_ammount for each insert on "comment" table which has the same id_topic of the topic.
I never used triggers, so anyone can help me?

well ,i am not special in mysql but i think you can do something like this
DELIMITER $$
declare #x table(id_topic int)
insert into #x '#x hold last insert'
select *
from comment
order by id desc
limit 1
update topic t join #x c
on c.id_topic =t.id_topic
set comments_ammount=comments_ammount+1
DELIMITER $$
DELIMITER ;

Related

Trigger After Insert ....to Update a Count(column)

I have a table "Comments" and a copy of it, call #Comments_copy (surprise!).
The table "comments" is linked to another one call #article" by a foreigner key as: comments.article_id = article.id.
In Comments_copy: I have a column COUNT(Comments_id).
I try to create a trigger AFTER INSERT into comments which will update the count in comments_copy.
I JUST begin in MySQL so I'm a bit lost in my code.
I guess my problem comes from my condition "WHERE". But I feel clueless to find out the right condition... :(
CREATE TABLE Comments_copy
SELECT Comments.id as C_id, article.id, COUNT(Comments.id) as Nb_comments
FROM Comments
RIGHT JOIN Article ON article.id = Comments.article_id
GROUP BY Article.id
ORDER BY Article.id ;
DELIMITER |
CREATE TRIGGER after_insert_comments AFTER INSERT
ON comments FOR EACH ROW
BEGIN
UPDATE Comments_copy
SET Nb_comments = Nb_comments +1
WHERE id = NEW.id ;
END |
DELIMITER ;
At the end, I expect to recalculate the count of comments JUST for the article concerned by the last comments entry.
Please try in this way.
Please notice that I changed END | to END; |
CREATE TRIGGER after_insert_comments
AFTER INSERT ON comments
FOR EACH ROW
BEGIN
UPDATE Comments_copy
SET Nb_comments = Nb_comments +1
WHERE id = NEW.id ;
END; |

UPDATE or INSERT on the same query without unique value

Hello Im trying to find a way the UPDATE or INSERT data with one query.
I have a table with like this:
+------+-------------+
| User | action_type |
+------+-------------+
| Jon | 1 |
| Kate | 2 |
| Jon | 4 |
+------+-------------+
I want to insert new value for Jon only if there is no values of Jon.
If I have values of Jon I want to update all the rows with Jon.
Ive read about INSERT ... ON DUPLICATE KEY UPDATE but I dont have unique values.
Thanks for helping.
you can count the entries for jon. If exists update else insert.
if you want to implement only using sql you can use an stored procedure
something like this:
CREATE PROCEDURE insertorupdate (IN name VARCHAR(20))
BEGIN
DECLARE numJon INT;
SELECT COUNT(*) INTO numJon FROM table WHERE User=name;
IF numJon > 0 THEN
// UPDATE ;
ELSE
// INSERT
END IF;
END
Then you can call you Store Procedure:
CALL insertorupdate('John');
If you can do it from your app you can call the same thing but separatelly. Do a select count, test if count if grater than 0 and then do the insert or the update on DB
Don't count like in user468891's answer. It might become a performance issue. Instead just check if an entry exists. As soon as an entry is found, the query returns true, count continues to find all records.
DELIMITER $$
CREATE PROCEDURE insertorupdate (IN name VARCHAR(20))
BEGIN
IF (EXISTS(SELECT 1 FROM table WHERE User = name)) THEN
// UPDATE...
ELSE
// INSERT...
END IF;
END $$
DELIMITER ;

Trigger - Error #1442 Can't update [MYSQL] [duplicate]

MySQL doesn't currently support updating rows in the same table the trigger is assigned to since the call could become recursive. Does anyone have suggestions on a good workaround/alternative? Right now my plan is to call a stored procedure that performs the logic I really wanted in a trigger, but I'd love to hear how others have gotten around this limitation.
Edit: A little more background as requested. I have a table that stores product attribute assignments. When a new parent product record is inserted, I'd like the trigger to perform a corresponding insert in the same table for each child record. This denormalization is necessary for performance. MySQL doesn't support this and throws:
Can't update table 'mytable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. A long discussion on the issue on the MySQL forums basically lead to: Use a stored proc, which is what I went with for now.
Thanks in advance!
You can actually up the rows in the same table as the trigger. The thread you linked to even has the solution.
For example:
TestTable ( id / lastmodified / random )
create trigger insert_lastmod
before insert on TestTable
for each row
set NEW.lastmodified = NOW();
insert into TestTable ( `random` ) values ( 'Random' );
select * from TestTable;
+----+---------------------+---------------------+
| id | lastmodified | random |
+----+---------------------+---------------------+
| 1 | 2010-12-22 14:15:23 | Random |
+----+---------------------+---------------------+
I suppose you could call the stored proc in your trigger. HOwever, if you want to update some fields in the same records that you are changing (such as an updatedby or lastupdated column) then you can do this in a beofre trigger according to the refernce manual. http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
This is a common operation for triggers and I find it difficult to believe it isn't supported.
If you want to update column that you don't read in trigger function, then as a workaround, you could put that column into separate table.
You can actually do that
The below is an example for same
DELIMITER $$
create trigger test2
before insert on ptrt
for each row
begin
if NEW.DType = "A" then
set NEW.PA = 500;
elseif NEW.DType = "B" then
set NEW.PA = 1000;
else
set NEW.PA = 0;
END IF;
END;$$
DELIMITER;
This worked for me :D
On Before / Update.
BEGIN
SET NEW.DateTimeUpdated = NOW();
END

Increment Table ID Field with Bitwise Counting

I am working on a project where I need my ID column to be a power of 2 (1,2,4,8,16..). I know that we cannot offset the auto_increment but for simple addition/subtraction in my.cnf.
Example:
id
----
1
2
4
8
16
32
64
128
etc
One of the ideas I had was to use the auto increment functionality as the base, and then create a trigger to apply the power of 2 and update the new ID, but unfortunately, it is not working:
DELIMITER $$
CREATE TRIGGER testbitcompatid BEFORE INSERT ON Table
FOR EACH ROW
BEGIN
SET NEW.id = pow(NEW.id, 2)
END;
$$
DELIMITER ;
Because the BEFORE INSERT has not yet generated the AUTO_INCREMENT id, the AUTO_INCREMENT will always return 0, essentially causing no change on the columns.
I also tried AFTER INSERT:
DELIMITER $$
CREATE TRIGGER testbitcompatid AFTER INSERT ON Table
FOR EACH ROW
BEGIN
SET Table.id = pow(NEW.id, 2) WHERE id = NEW.id;
END;
$$
DELIMITER ;
But this failed because you cannot change values of the table which the trigger is applied to during an AFTER INSERT.
Scratching my head, but I am sure someone else has a great way of accomplishing this.
To work around all the issues above, I was able to construct the following which works great!
DELIMITER $$
CREATE TRIGGER testbitcompatid BEFORE INSERT ON Table
FOR EACH ROW
BEGIN
SET #LAST_ROW = (SELECT MAX(id) FROM Table);
SET NEW.id = CASE WHEN #LAST_ROW IS NULL THEN 1 ELSE #LAST_ROW * 2 END;
END;
$$
DELIMITER ;
Pretty much, we take the highest id, grab the log(2) of it which gives us the corresponding AUTO_INCREMENT id. We then add 1, and power that up to 2.
I hope this helps prevent some headache down the road for others.

MySQL triggers cannot update rows in same table the trigger is assigned to. Suggested workaround?

MySQL doesn't currently support updating rows in the same table the trigger is assigned to since the call could become recursive. Does anyone have suggestions on a good workaround/alternative? Right now my plan is to call a stored procedure that performs the logic I really wanted in a trigger, but I'd love to hear how others have gotten around this limitation.
Edit: A little more background as requested. I have a table that stores product attribute assignments. When a new parent product record is inserted, I'd like the trigger to perform a corresponding insert in the same table for each child record. This denormalization is necessary for performance. MySQL doesn't support this and throws:
Can't update table 'mytable' in stored function/trigger because it is already used by statement which invoked this stored function/trigger. A long discussion on the issue on the MySQL forums basically lead to: Use a stored proc, which is what I went with for now.
Thanks in advance!
You can actually up the rows in the same table as the trigger. The thread you linked to even has the solution.
For example:
TestTable ( id / lastmodified / random )
create trigger insert_lastmod
before insert on TestTable
for each row
set NEW.lastmodified = NOW();
insert into TestTable ( `random` ) values ( 'Random' );
select * from TestTable;
+----+---------------------+---------------------+
| id | lastmodified | random |
+----+---------------------+---------------------+
| 1 | 2010-12-22 14:15:23 | Random |
+----+---------------------+---------------------+
I suppose you could call the stored proc in your trigger. HOwever, if you want to update some fields in the same records that you are changing (such as an updatedby or lastupdated column) then you can do this in a beofre trigger according to the refernce manual. http://dev.mysql.com/doc/refman/5.0/en/trigger-syntax.html
This is a common operation for triggers and I find it difficult to believe it isn't supported.
If you want to update column that you don't read in trigger function, then as a workaround, you could put that column into separate table.
You can actually do that
The below is an example for same
DELIMITER $$
create trigger test2
before insert on ptrt
for each row
begin
if NEW.DType = "A" then
set NEW.PA = 500;
elseif NEW.DType = "B" then
set NEW.PA = 1000;
else
set NEW.PA = 0;
END IF;
END;$$
DELIMITER;
This worked for me :D
On Before / Update.
BEGIN
SET NEW.DateTimeUpdated = NOW();
END