How to create trigger which increment colum value after inserting the row? - mysql

I have a database in MySQL. Here is SQL query to create it http://paste.org.ru/?xzctqi
Here is main table books. All I need to do is when I add some book, I choose publisher ID for it. After adding books, I need loop through all records in this table and increment column publisher_books_amount for all rows, which has same publisher as in currently added row.
+----+-------+--------+------------------------+-----------+
| id | title | author | publisher_books_amount | publisher |
+----+-------+--------+------------------------+-----------+
| 1 | Book1 | 1 | 0 | 1 |
| 2 | Book2 | 2 | 0 | 1 |
| 3 | Book3 | 1 | 0 | 2 |
| 4 | Book4 | 3 | 0 | 3 |
| 5 | Book1 | 3 | 0 | 1 |
+----+-------+--------+------------------------+-----------+
I've created trigger
DROP TRIGGER IF EXISTS `insert_trigger`;
DELIMITER |
CREATE TRIGGER `insert_trigger` AFTER INSERT ON books
FOR EACH ROW
BEGIN
UPDATE books SET publisher_books_amount = (publisher_books_amount + 1)
WHERE publisher = NEW.publisher;
END;
|
DELIMITER ;
But when I'm trying to add book, MySQL provides me with an error.
Can't update table 'books' in stored function/trigger because it is
already used by statement which invoked this stored function/trigger.
Don't ask me why do I have denormalized DB. I just need structure described above.
BTW I need to create same triggers after deleting and updating rows. If there are some problems with that, could you help me with it too?
Sincerely, Dmitriy.

Update inside a loop is not allowed, because it goes to infinite loop.
Try your triiger without update,with only set value this=this.

Related

MySQL TRIGGER: Delete dependent rows from the same table

I create a trigger in MySQL to delete all rows that depend on that OLD row.
Some menu items can be a sub-menu item, so the field menu_in has the parent item menu_id.
CREATE TRIGGER DEL_MENU_DEPENDENCIES
BEFORE DELETE ON menu
FOR EACH ROW BEGIN
DELETE FROM menu WHERE menu_in = OLD.menu_id;
END
But I get an error:
General error: 1442 Can't update table 'menu' in stored function/trigger because it is already used by statement which invoked this stored function/trigger
I already try "AFTER" but is the same problem.
This are the fields in table:
menu_id | menu_in | name
I search in Google but I did not find a solution.
It seems that it has to do with the possibility of creating an infinite loop.
But apparently the loop would stop if there are no more rows. Right?
Thank you in advance for all your attention.
EDIT
+---------+---------+------+
| menu_id | menu_in | name |
+---------+---------+------+
| 1 | 0 | mn1 |
+---------+---------+------+
| 2 | 0 | mn2 |
+---------+---------+------+
| 3 | 1 | mn3 |
+---------+---------+------+
| 4 | 1 | mn4 |
+---------+---------+------+
| 5 | 4 | mn5 |
+---------+---------+------+
| 6 | 2 | mn6 |
+---------+---------+------+
| 7 | 5 | mn7 |
+---------+---------+------+
Imagine that I need to delete row menu_id = 1. It would delete lines 3, 4, 5 and 7. Because they create a chain.
With a trigger in MySQL it would be great to do this. I would need just to delete one row, trigger would do the rest.
Thank you.
You can't do this with a trigger in MySQL or MariaDB.
https://dev.mysql.com/doc/refman/en/stored-program-restrictions.html says:
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.
You could accomplish what you describe by using a foreign key with the ON DELETE CASCADE option. Read https://dev.mysql.com/doc/refman/en/create-table-foreign-keys.html#foreign-key-referential-actions for details.

Mysql find root parent of shared post

I have to manage sharing-post like on Facebook here is how I intend to do it.
I have a table which contains articles with a parent_id field and I would like to change state of all shared articles to 0 when parent is deleted(when parent state = 0)
articles
+----+-----------+--------------+-------+--------+
| id | content | user_id | parent_id | state |
+----+-----------+--------------+-------+--------+
| 1 | content | 2 | null | 1 |
| 2 | content | 5 | null | 1 |
| 3 | content | 4 | 2 | 1 |
| 4 | content | 6 | null | 1 |
| 5 | content | 7 | 1 | 1 |
| 6 | content | 1 | 3 | 1 |
| ...| ... | ... | ... | ... |
+----------------+---------+------------+--------+
Example according to the articles table above:
User 4 shares article 2 and user 1 shares article 3 which is a child of the article 2. So when article 2(root article) is deleted(his state change to 0) all child articles(3 & 6) state have to also change to 0.
How to accomplish this ?
Any other way to manage sharing post will be great appreciated
I think you can program a trigger on delete:
Documentation: https://dev.mysql.com/doc/refman/5.7/en/create-trigger.html
There's an example:
BEFORE INSERT ON articles
FOR EACH ROW
BEGIN
UPDATE articles SET parent_id = 0 WHERE parent.id = OLD.parent_id;
END
If you need the trigger on multiple tables, you can program a stored procedure and call it on the trigger instead of programming the query on every table.
Also, if you want to avoid having lost / unlinked records, you can have a foreign key if you use INNODB tables. With a foreign key, you cannot insert a parent_id who not exists, or you cannot delete a register if they have any childs.
You can check documentation about foreign keys here: https://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html

MySQL create trigger on insert in tbl1 also insert to tbl2

I'm currently working with a client that wants their database to duplicate info into a second table in a different format when it is initially inserted.
Basically like the following:
Table 1
| ID | NAME | EMAIL | password |
--------------------------------------
| 1 | david | x#x.co | asx234 |
| 2 | anthony | y#x.co | 24gss3 |
| 3 | jillian | z#x.co | hdfg5d |
Every time a row gets inserted into table 1 they also want to take that information from table 1 and add it to Table 2
Table 2
| ID | NAME | EMAIL | password | signature | level | lastenter | register_date |
-----------------------------------------------------------------------------------------------
| 1 | david | x#x.co | asx234 | text | 3 | 0000-00-00 | Date of insert |
| 2 | anthony | y#x.co | 24gss3 | text | 3 | 0000-00-00 | Date of insert |
| 3 | jillian | z#x.co | hdfg5d | text | 3 | 0000-00-00 | Date of insert |
How do I set up a trigger to insert the data into Table 2 whenever a row is inserted into table 1?
Thanks!
Some thoughts below, but the trigger would look something like this:
DELIMITER $$
DROP TRIGGER IF EXISTS trgMyNewTrigger $$
CREATE TRIGGER trgMyNewTrigger AFTER INSERT ON Table1
FOR EACH ROW
BEGIN
INSERT into Table2 (ID,NAME,EMAIL,`password`,signature,`level`,lastenter,register_date) VALUES (
new.ID, new.NAME, new.EMAIL, new.password, 'text', 3, '0000-00-00', CURDATE() );
END $$
DELIMITER ;
This is not a great solution. Triggers in general can cause some nasty issues and limit your capabilities down the road. It would be better to reconsider the design of the table to be inclusive of the data you need, have the application perform the extra step or use some sort of ETL process to get the data at set intervals.
I will all assume the clear text passwords are for the example.

MySQL second auto increment field based on foreign key

I've come across this problem numerous times but haven't found a "MySQL way" to solve the issue as such - I have a database that contains users and reports. Each report has an id which I display as a report number to my users.
The main complaint is that users are confused as to why reports have gone missing from their system. This is not actually the case. It is actually that they are recognizing a gap between their IDs and assume that these are missing reports, when in actual fact, it is simply becasue another user has filled in this auto-incrementing gap.
I need to know if there is a way to do this in MySQL:
Is it possible that I can have a second auto-increment field called report_number which is based on a user_id field which has a different set of auto-increments per user?
e.g.
|------|---------|---------------|
| id | user_id | report_number |
|------|---------|---------------|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 1 | 4 |
| 6 | 1 | 5 |
| 7 | 2 | 2 |
| 8 | 3 | 1 |
| 9 | 3 | 2 |
|------|---------|---------------|
I am using InnoDB for this as it is quite heavily weighted with foreign-keys. It appears to complain when I add a second auto increment field, but I wasn't sure if there was a different way to do this?
MyISAM supports the second column with auto increment, but InnoDB doesn't.
For InnoDB you might create a trigger BEFORE INSERT to get the max value of the reportid and add one to the value.
DELIMITER $$
CREATE TRIGGER report_trigger
BEFORE INSERT ON reports
FOR EACH ROW BEGIN
SET NEW.`report_id` = (SELECT MAX(report_id) + 1 FROM reports WHERE user_id = NEW.user_id);
END $$
DELIMITER ;
If you can use MyISAM instead, in the documentation of MySQL page there is an example:
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
CREATE TABLE animals (
grp ENUM('fish','mammal','bird') NOT NULL,
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (grp,id)
) ENGINE=MyISAM;
INSERT INTO animals (grp,name) VALUES
('mammal','dog'),('mammal','cat'),
('bird','penguin'),('fish','lax'),('mammal','whale'),
('bird','ostrich');
SELECT * FROM animals ORDER BY grp,id;
Which returns:
+--------+----+---------+
| grp | id | name |
+--------+----+---------+
| fish | 1 | lax |
| mammal | 1 | dog |
| mammal | 2 | cat |
| mammal | 3 | whale |
| bird | 1 | penguin |
| bird | 2 | ostrich |
+--------+----+---------+
Right one with IFNULL:
DELIMITER $$
CREATE TRIGGER salons_trigger
BEFORE INSERT ON salon
FOR EACH ROW BEGIN
SET NEW.salon_id = IFNULL((SELECT MAX(salon_id) + 1 FROM salon WHERE owner = NEW.owner), 1);
END $$
DELIMITER ;
I think mysql doesnt support two auto_increment columns. you can create report number using information schema.
select NULL from information_schema.columns
MySQl does not support two auto incremented fields, if you need then create another table, set the other field which you want to be as auto incremented and you must set up a relationship with these two tables.

MySQL Multi Duplicate Record Merging

A previous DBA managed a non relational table with 2.4M entries, all with unique ID's. However, there are duplicate records with different data in each record for example:
+---------+---------+--------------+----------------------+-------------+
| id | Name | Address | Phone | Email | LastVisited |
+---------+---------+--------------+---------+------------+-------------+
| 1 | bob | 12 Some Road | 02456 | | |
| 2 | bobby | | 02456 | bob#domain | |
| 3 | bob | 12 Some Rd | 02456 | | 2010-07-13 |
| 4 | sir bob | | 02456 | | |
| 5 | bob | 12SomeRoad | 02456 | | |
| 6 | mr bob | | 02456 | | |
| 7 | robert | | 02456 | | |
+---------+---------+--------------+---------+------------+-------------+
This isnt the exact table - the real table has 32 columns - this is just to illustrate
I know how to identify the duplicates, in this case i'm using the phone number. I've extracted the duplicates into a seperate table - there's 730k entires in total.
What would be the most efficient way of merging these records (and flagging the un-needed records for deletion)?
I've looked at using UPDATE with INNER JOIN's, but there are several WHERE clauses needed, because i want to update the first record with data from subsequent records, where that subsequent record has additional data the former record does not.
I've looked at third party software such as Fuzzy Dups, but i'd like a pure MySQL option if possible
The end goal then is that i'd be left with something like:
+---------+---------+--------------+----------------------+-------------+
| id | Name | Address | Phone | Email | LastVisited |
+---------+---------+--------------+---------+------------+-------------+
| 1 | bob | 12 Some Road | 02456 | bob#domain | 2010-07-13 |
+---------+---------+--------------+---------+------------+-------------+
Should i be looking at looping in a stored procedure / function or is there some real easy thing i've missed?
U have to create a PROCEDURE, but before that
create ur own temp_table like :
Insert into temp_table(column1, column2,....) values (select column1, column2... from myTable GROUP BY phoneNumber)
U have to create the above mentioned physical table so that u can run a cursor on it.
create PROCEDURE myPROC
{
create a cursor on temp::
fetch the phoneNumber and id of the current row from the temp_table to the local variable(L_id, L_phoneNum).
And here too u need to create a new similar_tempTable which will contain the values as
Insert into similar_tempTable(column1, column2,....) values (Select column1, column2,.... from myTable where phoneNumber=L_phoneNumber)
The next step is to extract the values of each column u want from similar_tempTable and update into the the row of myTable where id=L_id and delete the rest duplicate rows from myTable.
And one more thing, truncate the similar_tempTable after every iteration of the cursor...
Hope this will help u...