recursive update trigger is not working properly - mysql

I have created 2 tables abc and xyz. Both table are having the same data as shown below.
Table abc:
+------+-------+--------+
| roll | name | status |
+------+-------+--------+
| 1 | john | I |
| 1 | ken | I |
| 1 | abel | I |
| 2 | aston | I |
| 2 | ron | I |
+------+-------+--------+
Table xyz:
+-------+-------+---------+
| roll1 | name1 | status1 |
+-------+-------+---------+
| 1 | john | I |
| 1 | ken | I |
| 1 | abel | I |
| 2 | aston | I |
| 2 | ron | I |
+-------+-------+---------+
The status in both tables can be updated to 'D' or 'E'. Suppose in table abc, if the status of John become 'D' then I need to take John's roll (that is 1) and update all the status in xyz to 'D' where roll1 = 1.
Similarly, suppose if the status of ron changed to 'E' in xyz table, then aston and ron status should be 'E' in table abc.
This need to be achieved using update triggers. I have created 2 update trigger for both the tables. The trigger used are
DELIMITER $$
DROP TRIGGER /*!50032 IF EXISTS */ `test2`.`abc_trigg`$$
create trigger `test2`.`abc_trigg` BEFORE UPDATE on `test2`.`abc`
for each row BEGIN
IF #__disable_trigger is null THEN
SET #__disable_trigger = 1;
if new.status = 'D' then
update xyz set status1='D' where roll1 = new.roll;
elseif new.status = 'E' then
update xyz set status1='E' where roll1 = new.roll;
end if;
end if;
end;
$$
DELIMITER ;
DELIMITER $$
DROP TRIGGER /*!50032 IF EXISTS */ `test2`.`xyz_trigg`$$
create trigger `test2`.`xyz_trigg` BEFORE UPDATE on `test2`.`xyz`
for each row BEGIN
IF #__disable_trigger is null THEN
SET #__disable_trigger = 1;
if new.status1 = 'D' then
update abc set status='D' where roll = new.roll1;
elseif new.status1 = 'E' then
update abc set status='E' where roll = new.roll1;
end if;
end if;
end;
$$
DELIMITER ;
But these triggers are not correct and I am not getting the expected output. Kindly guide me to fix the issue and help me to get the relevant output?

Related

Update Trigger using Where conditional and old. data

i have this homework to do and im into a problem creating triggers,
i have to make an update trigger so i have this table
+----+------+
| id | name |
+----+------+
| 1 | x |
+----+------+
| 2 | y |
+----+------+
| 3 | z |
+----+------+
so, the trigger i was thinking to do is this one
DELIMITER ||
CREATE TRIGGER updateID AFTER DELETE
ON personalData FOR EACH ROW
BEGIN
UPDATE personalData
SET id = id - 1
WHERE id > old.id;
END ||
DELIMITER ;
the idea is if some user is deleted the id would be updated, as an expample
if x is deleted the table would be
+----+------+
| id | name |
+----+------+
| 1 | y |
+----+------+
| 2 | z |
+----+------+
when i try to create the trigger the following error shows:
Error Code: 2014. Commands out of sync; you can't run this command now
I was searching for info, but i cant see whats wrong

SQL creating a trigger to insert and update table

I have three tables a test_cases table, a schedule table, an aggregate_summary table
test_cases
caseID | file_name
--------+-------------------------
1 | Test 1
2 | Test 2
3 | Test 3
schedule
| scheduleID | caseID | schedule_time
+------------+--------+---------------------
| 1 | 1 | 2016-02-29 02:15:00
| 2 | 2 | 2016-02-29 12:00:00
| 3 | 3 | 2016-02-27 12:00:00
| 4 | 2 | 2016-02-25 07:26:00
| 5 | 1 | 2016-02-26 07:37:00
| 6 | 2 | 2016-02-27 07:39:00
| 7 | 2 | 2016-02-28 07:25:00
| 8 | 1 | 2016-02-29 08:38:00
| 9 | 2 | 2016-02-29 07:08:00
aggregate_summary which has start_time and file name and other fields
I want to create a trigger so after a test is scheduled it puts the schedule_time into start_time (on aggregate_summary table) and puts file_name(from test_cases) into file_name field on aggregate_summary table.
I cannot get the syntax right:
CREATE TRIGGER OnScheduleInsert AFTER INSERT ON schedule FOR EACH ROW BEGIN INSERT INTO aggregate_summary (start_time) VALUES(NEW.schedule_time)
UPDATE aggregate_summary SET file_name=(SELECT file_name FROM test_cases WHERE NEW.caseID=test_cases.caseID) END;
To execute queries in the body of the trigger they must be separated by semicolons. In order to have your MySQL client not interpret the semicolon as the end of the CREATE TRIGGER statement, you might first need to change the delimiter to something other than a semicolon, then change it back afterwards.
DELIMITER //
CREATE TRIGGER OnScheduleInsert
AFTER INSERT ON schedule
FOR EACH ROW
BEGIN
INSERT INTO aggregate_summary (start_time) VALUES(NEW.schedule_time);
UPDATE aggregate_summary SET file_name=(SELECT file_name FROM test_cases WHERE NEW.caseID=test_cases.caseID);
END//
DELIMITER ;
I don't think the body of the trigger quite does what you want it to but I'm afraid I'm not really clear what the desired behaviour of the trigger is. Still, at least it's now syntactically valid.

How to delete rows inserted unintentionally with a given column value

I am a beginner with MySQL. I made a stored procedure to insert 1,000 random names from a table. It has 3 fields with num, course_name and grade. num is foreign key--as this was for a test purpose, I just kept incremented the num only. So I didn't mark it as a PRIMARY KEY/AUTO_INCREMENT. I called the procedure, and it inserted 1,000 random names in the table. Unknowingly, I called the procedure again, and stopped it after some time. Then the table got 500 more entries after that previous 1000 entries. I wanted to delete the rows that created after the second procedure call.
Below is my statements in a stored procedure: (course_name and grade_details are additional tables with course names and grades.)
DELIMITER //
CREATE PROCEDURE course_grade(IN name_entries int)
BEGIN
DECLARE i int DEFAULT 0;
DECLARE course varchar(20);
DECLARE crs_grade char(1);
gradeloop : LOOP
SELECT name INTO course FROM course_name ORDER BY rand() LIMIT 1;
SELECT grade INTO crs_grade FROM grade_details ORDER BY rand() LIMIT 1;
INSERT INTO tbl_grade(fk_int_roll_no,vchr_course,vchr_grade)
VALUES (i+1,course,crs_grade);
SET i = i + 1;
IF (i=name_entries)
THEN LEAVE gradeloop;
END IF;
END LOOP gradeloop;
SELECT COUNT(*) FROM tbl_grade;
END //
DELIMITER ;
And my table is like :
+----------------+-------------+------------+
| fk_int_roll_no | vchr_course | vchr_grade |
+----------------+-------------+------------+
| 1 | AE | A |
| 2 | MECH | B |
| 3 | EC | A |
| . | .... | . |
| . | .... | . |
| 1000 | IT | E |
| 1 | MARINE | F |
| 2 | BIOTECH | F |
| . | .... | . |
| . | .... | . |
| . | .... | . |
| . | .... | . |
| 500 | RM | A |
+----------------+-------------+------------+
Wanted to delete the last 1 to 500 rows made by mistake!

MySQL AFTER Update trigger with New.col<> OLD.col

The goal here is to update and concatenate a text field from one table to another based on conditions. When a text col gets updated with some text from a user form, run After update trigger.
The trigger runs but updates all the columns not just the one that has changed.Trying to understand how to just update the correct row only.
Here's what i have so far-
SQLFiddle
| ID | SUBID | SWNOTES |
|----|-------|---------| Table 1
| 1 | 40 | test |
| 2 | 60 | |
| ID | SUBID | CONTENT | SWFLAG |
|----|-------|---------|--------|
| 1 | 40 | hello | 0 | Table 2
| 2 | 60 | nothing | 0 |
CREATE TRIGGER `updatecontentnotes` AFTER UPDATE ON `tab1`
FOR EACH ROW
BEGIN
IF New.swnotes <> OLD.swnotes
THEN
Update `tab2`
Inner Join `tab1` ON `tab2`.`subid` = `tab1`.`subid`
Set `tab2`.`swflag` = '1',`tab2`.`content` = CONCAT(`tab2`.`content`, `tab1`.`swnotes`)
Where `tab2`.`subid` = `tab1`.`subid` AND `tab2`.`swflag` = '0';
END IF;
END//
And if I update the table with say:
Update `tab1`
set `swnotes` = "new"
where `subid` = '60'
I get :
| ID | SUBID | CONTENT | SWFLAG |
|----|-------|------------|--------|
| 1 | 40 | hellotest | 1 |
| 2 | 60 | nothingnew | 1 |
Now I know it is doing what I am telling it to do. I want to update just the row that is updated. Thanks for any help on this.
Since the contents of your trigger will run for every row on tab1, you need to be more restrictive in your WHERE clause so that it will only affect the rows that have been updated. Right now it updates every row on tab2
Try adding this to your trigger SQL:
From:
Where `tab2`.`subid` = `tab1`.`subid` AND `tab2`.`swflag` = '0';
To:
Where `tab2`.`subid` = `tab1`.`subid` AND `tab2`.`swflag` = '0' AND `tab2`.`id` = OLD.id;
This produces the results that I think you are looking for:
| ID | SUBID | CONTENT | SWFLAG |
|----|-------|------------|--------|
| 1 | 40 | hello | 0 |
| 2 | 60 | nothingnew | 1 |
The updated SQLFiddle is here:
http://sqlfiddle.com/#!2/9fa2d2/1/0

SELECT and UPDATE same rows in MYSQL stored procedure

I'm working on a application for which I need to read m rows at a time out of total 'N' rows where m < N. Every time I read 'm' rows I have to set their status as read in the same table.
For example consider following table
+------+-------------------------+--------------------------+----------+-------+---------+------+
| ID | from_email_address | to_email_address | subject | body | inqueue | sent |
+------+-------------------------+--------------------------+----------+-------+---------+------+
| 1 | 0120sushil#gmail.com | kumar.sushil#outlook.com | Subject1 | Body1 | 0 | 0 |
| 2 | 0120ksushil#gmail.com | kumar.sushil#outlook.com | Subject1 | Body1 | 0 | 0 |
| 3 | shivaseth1#gmail.com | kumar.sushil#outlook.com | Subject1 | Body1 | 0 | 0 |
| 4 | shivaseth1#gmail.com | amanrajg#outlook.com | Subject1 | Body1 | 0 | 0 |
| 5 | shivamprakash#gmail.com | amanrajg#outlook.com | Subject1 | Body1 | 0 | 0 |
| 6 | shivamprakash#gmail.com | poorvanagpal#outlook.com | Subject1 | Body1 | 0 | 0 |
| 7 | shivankgupta#gmail.com | poorvanagpal#outlook.com | Subject1 | Body1 | 0 | 0 |
+------+-------------------------+--------------------------+----------+-------+---------+------+
I want to read lets say 3 rows at a time and once I have read the rows I want to set inqueue status of those rows as 1.
I can use following query in stored procedure to select the rows
select * from EmailQueue where inqueue=1 LIMIT 3
After this how to update the same rows and set their inqueue to 1.
EDIT
Here is the stored procedure I created which is giving some error.
DELIMITER $$
DROP PROCEDURE IF EXISTS GetUnsentMails;
CREATE PROCEDURE GetUnsentMails()
BEGIN
START TRANSACTION;
CREATE TEMPORARY TABLE temp_EmailQueue AS SELECT * FROM EmailQueue WHERE inqueue = 0 LIMIT 5 FOR UPDATE;
UPDATE EmailQueue SET inqueue=1 where id in (SELECT id from temp_EmailQueue) AND inqueue = 0;
COMMIT;
END
It gives following error on calling
ERROR 1746 (HY000): Can't update table 'emailqueue' while 'temp_EmailQueue' is being created.
Suggesting to use Transaction and "SELECT FOR UPDATE" to fulfill your requirements.
Please refer following links for the examples:
MySQL 'select for update' behaviour
http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
http://www.sqlines.com/mysql/how-to/select-update-single-statement-race-condition
UPDATE - Added the QUERY EXAMPLE:
Example:
.......
#Before starting procedure
.......
START TRANSACTION;
CREATE TEMPORARY TABLE zzz_EmailQueue AS SELECT * FROM EmailQueue WHERE inqueue=1 LIMIT 3 FOR UPDATE;
.....
.....
#Section for other activities....
.....
.....
UPDATE EmailQueue SET inqueue=<<New_Value>> WHERE id IN (SELECT id FROM zzz_EmailQueue) AND inqueue=1;
COMMIT;
.......
#Remaining lines of Prodecure
.......
Update **
**Try with following method:
DECLARE v_EmailQueue_ID DOUBLE;
SELECT ID INTO v_EmailQueue_ID FROM EmailQueue WHERE inqueue = 0 LIMIT 1 FOR UPDATE;
UPDATE EmailQueue SET inqueue=1 WHERE id=v_EmailQueue_ID AND inqueue = 0;