mysql update trigger: update "some" other rows - mysql

Table "Book":
bookid | title
1 | Java
2 | MySQL
3 | Zen
Table "BestPage":
pageid | bookid | isbestpage
1 | 1 | 0
2 | 1 | 0
3 | 1 | 1
4 | 2 | 0
5 | 2 | 1
6 | 2 | 0
So some books may have a "bestpage", but only one.
Now I would probably need a beforeupdate trigger so when I update the row with pageid 2, and set isbestpage = 1,
then all the other pages BUT ONLY FOR THAT BOOK will have isbestpage set to 0.
Something like:
for each row
begin
if old.isbestpage = 1 and -- here I want to tell that **only for the current book** !
then
set new.isbestpage = 0
or something like that.
That is, if I mark a page as bestpage, all other pages within this book should be set as not a best page.
Thanks.

Unfortunately you can't do that in a MySql trigger
According to E.1. Restrictions on Stored Programs
Within a stored function or trigger, it is not permitted to modify a
table that is already being used (for reading or writing) by the
statement that invoked the function or trigger.
What you can do though to alleviate some pain is to create a stored procedure like this
DELIMITER $$
CREATE PROCEDURE sp_update_bestpage(IN pid INT)
BEGIN
UPDATE bestpage p JOIN
bestpage p1 ON p.bookid = p1.bookid
SET p.isbestpage = 0
WHERE p1.pageid = pid AND p.pageid <> pid;
UPDATE bestpage
SET isbestpage = 1
WHERE pageid = pid;
END $$
DELIMITER ;
And then use it
CALL sp_update_bestpage(2);
SQLFiddle

Related

Creating map and use that within the MySQL stored procedure

I am working on a migration project and the data needs to be migrated from system A to system B. The id's in system A and system B will be different. So maintaining a table with source and target column.
As part of the migration, For each record from source A, I need to go to the mapping table to find the corresponding target value. I am just trying avoid querying the mapping table for each query. Is there any way to store the mapping table as a key value map in a stored procedure and query the map as opposed to going to the table directly?
I was searching for collections in MySQL stored procedure, but didn't find anything.
Database A:-
Table : employee
---------------------------------
id | name | email |
---------------------------------
10021 | First1 | first#test.com |
---------------------------------
10035 | First 2| first#test.com |
---------------------------------
Database B:-
Table : employee
---------------------------------
id | name | email |
---------------------------------
1 | First1 | first#test.com |
---------------------------------
2 | First 2| first#test.com |
---------------------------------
Table : emp_mapping
----------------------
source_id | target_id|
----------------------
10021 | 1 |
----------------------
10035 | 2 |
----------------------
Stored Procedure for Migration
DELIMITER //
CREATE PROCEDURE LoadEmployees()
BEGIN
DECLARE db1_empl_id INT;
DECLARE db1_empl_name VARCHAR(20);
DECLARE db1_empl_email VARCHAR(40);
DECLARE db2_empl_id INT;
DECLARE cur CURSOR FOR SELECT id, name, email FROM db1.employees;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET cursor_finished = 1;
open cur;
cur_loop: LOOP
FETCH cur INTO db1_empl_id, db1_empl_name, db1_empl_email;
IF cursor_finished = 1 THEN
LEAVE cur_loop;
END IF;
-- cursor loop statements
-- I would like to move this to a map instead of querying for each record
select target_id into db2_empl_id from db2.emp_mapping where source_id = db1_empl_id;
insert into db2.employee(id,name,email) values(db2_empl_id, db1_empl_name, db1_empl_email);
SET cursor_finished = 0; -- hence reset this value for cursor.
end LOOP;
close cur;
END //
DELIMITER ;

how to get the updated row from a table when calling a trigger after update

This is my table structure
mysql> select * from product_table;
+----------------+---------------------+
| product_number | product_description |
+----------------+---------------------+
| 1 | product one |
| 2 | product two |
| 3 | product three |
| 9 | product five |
| 10 | product six |
| 11 | product six |
+----------------+---------------------+
I want to say update a row say 9th product number from the table like this
UPDATE product_table SET product_description ="product seven" WHERE product_number=9;
So that in the trigger i can get the corresponding updated product number from the table product_table
I wrote the trigger like this and it got created without any errors.
DELIMITER //
CREATE TRIGGER product_table_update
AFTER UPDATE
ON product_table
FOR EACH ROW
BEGIN
DECLARE l_product_number INT;
set #l_table_name = 'product_table';
set #l_action = 'updation';
SET #l_table_column = 'product_description';
select new.product_number into #l_product_number from product_table;// here is i think where the problem is , i am trying to fetch the updated row to l_product_number
IF (OLD.product_description <> NEW.product_description) THEN
SET #oldval = OLD.product_description;
SET #newval = NEW.product_description;
select concat(#oldval,#newval) into #l_description;
END IF;
INSERT INTO audit_table_test
( table_name,
changed_row_id,
action,
table_column,
change_desciption,
change_time
)
VALUES
( #l_table_name,
#l_product_number,
#l_action,
#l_table_column,
#l_description,
NOW()
);
END; //
DELIMITER ;
then when i tried to update like this
UPDATE product_table SET product_description ="product seven" WHERE product_number=11;
This error is showing
ERROR 1172 (42000): Result consisted of more than one row
I know the problem has to be in this code
select new.product_number into #l_product_number from product_table;// here is i think where the problem is , i am trying to fetch the updated row to l_product_number
Please someone help me to get the update row on calling this trigger
Try:
...
SET #l_table_column = 'product_description';
/*
here is i think where the problem is , i am trying to fetch the
updated row to l_product_number
*/
-- select new.product_number into #l_product_number from product_table;
SET #l_product_number := NEW.product_number;
IF (OLD.product_description <> NEW.product_description) THEN
...

mysql constraint or trigger

How to make sure that a couple of rows (A,B) values can be duplicated but can have only one corresponding value in row C in the same table ?
Suppose i am inserting these rows in this order this the output i want to have.
EDIT:
what i want is that when A,B,C is inserted for the first time value in C will be the unique possible value for the couple (A,B)
this means, if i, insert (0,0) with C = 1 when there is no other (0,0) couples in (A,B) then the row is accepted.But if i add (0,0) for the second(third ..) time; then C has to be equal to 1.
example :
A | B | C | D | F ...
_________________
0 | 0 |1
0 | 0 |1
0 | 0 |2 --> not allowed
1 | 0 |3 --> allowed
1 | 0 |2 --> not allowed
1 | 0 |3 --> allowed
try this trigger
DELIMITER $$
CREATE TRIGGER wtf_dupes BEFORE INSERT ON your_table
FOR EACH ROW
BEGIN
SET #ok := TRUE;
SELECT FALSE INTO #ok FROM your_table
WHERE
A = new.A
AND B = new.B
AND C <> new.C
LIMIT 1
;
IF NOT #ok THEN
SIGNAL SQLSTATE '23000' SET MESSAGE_TEXT = 'YourMessageAboutDupeError';
END IF;
END $$
DELIMITER ;
about how to trap signals you should do your own investigation:
http://dev.mysql.com/doc/refman/5.5/en/signal.html#signal-effects
Although there is a way to create a trigger that checks another table or view
for already existing value combinations, there is a question on canceling insert from within a trigger in MySQL and the accepted answer says that there is no such feature. So I think you have to implement this in application logic or move the insert to a procedure.

Case statement in stored procedure - Unknown System Variable

I'm trying to use a case statement to update a column based on the value of another column. My table called 'rma' in MySQL is as follows:
ID | rma_number | serial_number | ref_status_id
1 | 9898 | 123456 | 19
2 | 7869 | 098768 | 3
Here is my stored procedure:
CREATE DEFINER=`admin`#`localhost` PROCEDURE `delete_update_rma`(in selectedID int, in selectedRMAID int)
begin
declare rmaStatus int(5);
select ref_status_id into rmaStatus
from rma
where id = selectedRMAID;
case rmaStatus
when 19 then
set ref_status_id = 0;
end case;
delete from dropbox where id = selectedID;
end
When I try to save to create the procedure I receive the error #1193 - Unknown system variable 'ref_status_id'.
Can anybody help me identify what may be wrong with my stored procedure?
Try this:
CREATE DEFINER=`admin`#`localhost` PROCEDURE `delete_update_rma`(IN selectedID INT, IN selectedRMAID INT)
BEGIN
UPDATE rma
SET ref_status_id =
CASE ref_status_id
WHEN 19 THEN 0
WHEN 3 THEN 2
ELSE ref_status_id
END
WHERE id = selectedRMAID;
DELETE FROM dropbox WHERE id = selectedID;
END
Check the SQL FIDDLE DEMO
OUTPUT
| ID | RMA_NUMBER | SERIAL_NUMBER | REF_STATUS_ID |
|----|------------|---------------|---------------|
| 1 | 12345 | 67898 | 0 |
| 2 | 45645 | 89056 | 2 |
The case syntax is correct, however you cannot change a database field inside a case statement, you need to use an update statement for that.
UPDATE rma
SET ref_status_id = 0
WHERE ref_status_id = 19
AND id = selectedrmaid;
You can only change local vars inside this kind of case statement.
Yours is a typical case of mixing procedural and query logic, a common error when doing stored procedures.
The line ==>
set ref_status_id = 0;
Is causing the error. You are treating set ref_status_id as a variable when its a column in the rma table.
What are you trying to do in that case statement? Since the checking for a hard coded values of 19 doesn't seem to align with what you are trying to do.

how to call a stored procedure using table data?

i want to create a stored procedure by using below requirement.
i tried and written a stored procedure it is working fine with the static values.
how a stored procedure will work with the dynamic values.
Please find my requirement here.
Create a stored proc “skillsparse” that accepts a string of text and and breaks it up into 1,2,3 word phrases.
a. For example: I love java because it’s fun should have these 15 phrases
i. I
ii. I love
iii. I love java
iv. Love
v. Love java
vi. Love java because
vii. Java
viii. Java because
ix. Java because it’s
x. Because
xi. Because it’s
xii. Because it’s fun
xiii. It’s
xiv. It’s fun
xv. fun
3. Store these phrases in a new table called: github_skills_phrases with fields: ID, userid, skills_id (from github_skills_source) and skills_phrase
4. Create a storedproc that compares the skills_phrases against the skills table (ref Table) and store the values into the github_skills table for each user. If possible, please maintain the source of where the skills came from (repodesc, repolang, starred, bio)
5. NOTE: Aside from the info in the new table Kishore is creating, you will also need to run the github_users.bio field against the Skillsparse procedure. You can start this first (for testing logic, etc) since the github_users.bio already exists and has data.
We don’t need to go this for users who have not yet been processed for skills
How i written is:
++++++++++++++++++++++++++++++++++++++++++++++++++++++
DELIMITER $$
CREATE procedure testing(IN id varchar(20),IN usr_id varchar(20),IN str varchar(200))
begin
DECLARE wordCnt varchar(20);
DECLARE wordCnt1 varchar(20);
DECLARE idx INT DEFAULT 1;
DECLARE splt varchar(200);
declare strng varchar(200);
create temporary table tmp.hello1(id varchar(200),usr_id varchar(200),st varchar(200));
set strng = str;
set wordCnt = LENGTH(trim(strng)) - LENGTH(REPLACE(trim(strng), ' ', ''))+1;
set wordCnt1 = LENGTH(trim(strng)) - LENGTH(REPLACE(trim(strng), ' ', ''))+1;
myloop: WHILE idx <= wordCnt DO
set splt = substring_index(trim(strng),' ',idx);
insert into tmp.hello1 values (id,usr_id,splt);
set idx=idx+1;
IF idx = 4 THEN
set strng = substring(trim(strng),length(substring_index(trim(strng),' ',1))+1);
set idx = 1;
set wordCnt = wordCnt -1;
END IF;
end while ;
insert into tmp.hello1 values (id,usr_id,trim(substring(trim(str),length(substring_index(trim(str),' ',wordCnt1-1))+1)));
end $$
Out put ::
mysql> call testing('10','200','I am the my fine the kks hhh nanj kell');
Query OK, 1 row affected (0.77 sec)
mysql> select * from hello1;
+------+--------+---------------+
| id | usr_id | st |
+------+--------+---------------+
| 10 | 200 | I |
| 10 | 200 | I am |
| 10 | 200 | I am the |
| 10 | 200 | am |
| 10 | 200 | am the |
| 10 | 200 | am the my |
| 10 | 200 | the |
| 10 | 200 | the my |
| 10 | 200 | the my fine |
........
..........
| 10 | 200 | kell |
+------+--------+---------------+
27 rows in set (0.00 sec)
my stored procedure is working fine with static values .how to call dynamically a stored procdure by using table data.
Please help me to write a stored procedure to calling with the table data.
If you means you need to call this stored procedure inside select statement on certain data table, this is not available.
You have two options:
1- transfer your procedure to function and then you can call it easily from inside the select statement.
2- write plsql code to call this procedure and you can check the below link about this point
oracle call stored procedure inside select