I have a simple mysql procedure below to delete data from a table based on an argument passed.
I am getting foreign constraint failed exception as the dependent data is not deleted.
I am forming a list of IDs to delete as i want to avoid full table scan on the table
when using sub queries.
Any help is appreciated.
CREATE PROCEDURE `deleteService`(IN serviceID LONG)
BEGIN
DECLARE rpslist varchar(512) DEFAULT "";
DECLARE finished INTEGER DEFAULT 0;
DECLARE rpsid varchar(512) DEFAULT "";
DECLARE rpsidcursor
CURSOR FOR
select id from rpsa where so_id in (select id from rpso where rps_id = serviceID);
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET finished = 1;
OPEN rpsidcursor; //fetch ids to delete
getRPSId: LOOP
FETCH rpsidcursor INTO rpsid;
IF finished = 1 THEN
LEAVE getRPSId;
END IF;
SET rpsid = concat("'",rpsid,"'"); -- form concatenated string of IDs
SET rpslist = CONCAT(rpsid,",",rpslist);
END LOOP getRPSId;
CLOSE rpsidcursor;
SET rpslist = substring(rpslist,1,length(rpslist) -1); -- remove last comma
DELETE from uach where rpsa_id in (rpslist); -- delete dependent data . forming the list to hit index
-- this statement fails bcos the delete above did not work and there is foreign constraint
DELETE from rpsa where rpselectedso_id in (select id from rpselectedso where rpaxnservice_id = serviceID);
END
Passing a CSV string variable like IN (variable) won't work because MySQL will see the variable as a single element and not multiple ids.
If you want to do such a thing, you should use dynamic queries.
Why not just use direct queries:
CREATE PROCEDURE `deleteService`(IN serviceID LONG)
BEGIN
delete
from uach
join rpsa on rpsa.id=uach.rpsa_id
join rpso on rpso.id=rpsa.so_id
where rpso.rps_id=serviceID;
delete
from rpsa
join rpselectedso on rpselectedso.id=rpsa.rpselectedso_id
where rpselectedso.rpaxnservice_id=serviceID;
END
Related
I searched a lot of doing a task but found no appropriate solution.
Basically the scenario is. I have a user_comment table in which there are 5 column(id,parent_id,user_comments,is_deleted,modified_datetime). There is a parent child relationship like 1->2,1->3,2->4,2->5,5->7 etc. Now i am sending the id from the front end and i want to update the column is_deleted to 1 and modified_datetime on all the records on
this id as well as the all the children and children's of children.
I am trying to doing this by using a recursive procedure. Below is the code of my procedure
CREATE DEFINER=`root`#`localhost` PROCEDURE `user_comments`(
IN mode varchar(45),
IN comment_id int,
)
BEGIN
DECLARE p_id INT DEFAULT NULL ;
if(mode = 'delete')
then
update user_comment set is_deleted = 1, modified_datetime = now()
where id = comment_id ;
select id from user_comment where parent_id = comment_id into p_id ;
if p_id is not null
then
SET ##GLOBAL.max_sp_recursion_depth = 255;
SET ##session.max_sp_recursion_depth = 255;
call user_comments('delete', p_id);
end if;
end if;
END
By using this procedure it give me an error of more than one row.
If i return the select query without giving it to variable then shows me the the appropriate results on the select query but i have to call this procedure recursively based on getting the ids of the select query.
I need help i have already passed 2 days into this.
I used cursor also. Below is the code of cursor
CREATE DEFINER=`root`#`localhost` PROCEDURE `user_comments`(
IN mode varchar(45),
IN comment_id int,
)
BEGIN
DECLARE p_emp int;
DECLARE noMoreRow INT;
DECLARE cur_emp CURSOR FOR select id from user_comment where parent_id = comment_id ;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET noMoreRow = 0;
if(mode = 'delete')
then
OPEN cur_emp;
LOOPROWS: LOOP
IF noMoreRow = 0 THEN
update user_comment set is_deleted = 1, modified_datetime = now() where id = comment_id
CLOSE cur_emp;
LEAVE LOOPROWS;
END IF;
FETCH cur_emp INTO p_emp;
update user_comment set is_deleted = 1, modified_datetime = now() where id = p_emp ;
SET ##GLOBAL.max_sp_recursion_depth = 255;
SET ##session.max_sp_recursion_depth = 255;
call user_comments('delete', p_emp);
END LOOP;
end if;
END
After using cursor i am getting a thread error.i don't know how can overcome this problem!!!
Mysql's documentation on select ... into varlist clearly says:
The selected values are assigned to the variables. The number of
variables must match the number of columns. The query should return a
single row. If the query returns no rows, a warning with error code
1329 occurs (No data), and the variable values remain unchanged. If
the query returns multiple rows, error 1172 occurs (Result consisted
of more than one row). If it is possible that the statement may
retrieve multiple rows, you can use LIMIT 1 to limit the result set to
a single row.
Since you wrote in the OP that a comment can be parent of many comments, using simple variables cannot be a solution. You should use a CURSOR instead, that can store an entire resultset.
You loop through the records within the cursos as shown in the sample code in the above link and call user_comments() in a recursive way.
UPDATE
If your receive
Error Code: 1436. Thread stack overrun
error, then you can do 2 things:
Increase the thread_stack setting in the config file and restart mysql server.
You can try to simplify your code to use less recursions and therefore less stack space. For example, when you fetch all children into the cursor, then rather calling the user_comments() recursively for each, you can set all direct children's status within the code and call the function recirsively on grand-childrens only (if any). You can also change your data structure and use nested set model to approach hierarchical structures.
Nested set model is more complex to understand, it is less resource intensive to traverse, but more resource intensive to maintain.
So, I'm getting an error about a function not being defined. It happens every time I try to use my counter variables to refer to specific entries in tables. I don't get it.
To be more clear, I was advised that in order to use loops with mysql I had to make a 'procedure' which I have done. the count and ingredientcount variables are references to the row being examined in the tables tDrinks and tUniqueingredients.
I am trying to generate a foreign key reference for the drink id from tDrinks in the table tDrinkMix. I want there to be an entry of the drink id for each instance of a unique ingredient in the drink. There are 16.5k drinks and 2.2k unique ingredients.
Right now it dies on SELECT id(count) FROM tDrinks. If I remove the (count) there it dies next on WHERE d_shopping(count).
The error thrown is #1305 and it says that the function DrinksDB.id is not defined
DROP PROCEDURE `test`//
CREATE DEFINER=`root`#`localhost` PROCEDURE `test`()
BEGIN
DECLARE count INT DEFAULT 0;
DECLARE ingredientcount INT DEFAULT 0;
WHILE count < 16532 DO
WHILE ingredientcount < 2202 DO
INSERT INTO tDrinkMix(count)
SELECT id(count) FROM tDrinks
WHERE d_shopping(count)
LIKE CONCAT('%',tUniqueingredients.ingredient(ingredientcount),'%');
SET ingredientcount = ingredientcount + 1;
END WHILE;
SET count = count + 1;
END WHILE;
END
So I'm working on refining this a bit, and I'm still not quite there. How can you tell this is my first database project? The following is getting closer I think: the procedure at least saves and looks like it might execute
delimiter //
CREATE DEFINER=`root`#`localhost` PROCEDURE `test`()
BEGIN
DECLARE count INT DEFAULT 0;
DECLARE ingredientcount INT DEFAULT 0;
WHILE count < 16532 DO
WHILE ingredientcount < 2202 DO
INSERT INTO tDrinkMix(drink_id)
SELECT id
FROM tDrinks
WHERE id = count
and
d_shopping
LIKE
(SELECT CONCAT (ingredient,'%') FROM tUniqueingredients WHERE id = ingredientcount);
SET ingredientcount = ingredientcount + 1;
END WHILE;
SET count = count + 1;
END WHILE;
END//
I believe the error is occurring because the parser is interpreting id(count) as a function. It's looking for a function in your database which I guess is DrinksDB. When you remove the (count) from id its moving to the next syntax error of d_shopping(count) and looks for a function with the name d_shopping in your database.
I appreciate I'm late in coming to this (I'm just scanning open issues) so it's probably not an issue any more. If its still a problem post a comment.
i have a trigger like below, the logic is to change FID status after fidRule status changed.
in my app, i update 1 row in each statement,
but i found sometimes(very rare) the trigger not firing.
ALTER TRIGGER [dbo].[triggerSetFIDStatus]
ON [dbo].[FIDRules]
AFTER UPDATE
AS
BEGIN
set nocount on
DECLARE #ruleStatus INT
DECLARE #newRuleStatus INT
DECLARE #FIDAlertStatus INT
DECLARE #FIDId INT
DECLARE #isFIDEnabled int
DECLARE #ruleId INT
SELECT #ruleStatus = deleted.alertStatus,
#FIDId = deleted.FIDID,
#ruleId = deleted.id
from
deleted
SELECT #newRuleStatus = inserted.alertStatus
from
inserted
SELECT #FIDAlertStatus = alertStatus,
#isFIDEnabled= isEnabled
FROM FID
WHERE id = #FIDId
IF #FIDAlertStatus <> #newRuleStatus
BEGIN
-- change FID-status by FIDRule-status
UPDATE [dbo].[FID] SET alertStatus=#newRuleStatus WHERE id=#FIDId
END
IF #newRuleStatus >= 0 AND #newRuleStatus <> #ruleStatus
UPDATE [dbo].[FIDRules] SET isAlertStatChanged=1, AlertStatChangeTime = SYSUTCDATETIME() WHERE id=#ruleId
END
The trigger will not be fired if the UPDATE statement fails or another triggers fails to execute before this trigger is fired.
One comment about your trigger itself:
You are expecting one records from DELETED which is not always correct.
Please make your trigger robust enough in case DELETED contains multiple records
-- What if deleted contains multiple records?
SELECT #ruleStatus = deleted.alertStatus,
#FIDId = deleted.FIDID,
#ruleId = deleted.id
FROM
deleted
You can either use SELECT TOP(1) or make sure your trigger is able to handle multiple records from the DELETED list.
I'm fairly new to SQL in general and even more so to MySQL and I've hit a stumbling block. I'm attempting to use a procedure to copy the value of one field to another if the original field is not null, this procedure is then called by triggers whenever the table is updated or has a new row inserted into it. Here is what I have so far:
-- WORK_NOTES_PROCEDURE - This copies the contents of the estimate notes to the work order notes if the original estimate had any notes with it.
DROP PROCEDURE IF EXISTS 'WORK_NOTES_PROCEDURE';
DELIMITER $$
CREATE PROCEDURE WORK_NOTES_PROCEDURE()
BEGIN
DECLARE var_temp VARCHAR(50);
SET var_temp := (SELECT ESTIMATE_NOTES FROM ESTIMATES WHERE ESTIMATES.ESTIMATE_NUMBER = WORK_ORDERS.ESTIMATE_NUMBER);
IF var_temp IS NOT NULL THEN
UPDATE WORK_ORDERS SET WORK_ORDER_NOTES = var_temp WHERE WORK_ORDERS.ESTIMATE NUMBER = ESTIMATES.ESTIMATE_NUMBER;
END IF;
END$$
DELIMITER ;
Absolutely any help would be appreciated, the error I'm getting is a syntax error for the line where I'm assigning a value to var_temp.
try,
SET var_temp = (SELECT ESTIMATE_NOTES
FROM ESTIMATES INNER JOIN WORK_ORDERS
ON ESTIMATES.ESTIMATE_NUMBER = WORK_ORDERS.ESTIMATE_NUMBER
LIMIT 1);
I want to generate PK through trigger as it is custom PK.
It is like depending on the member type field, I want to generate member id which is PK.
e.g. if new record's member type is DGIA, then member id will be DGIA1, DGIA2, DGIA3 ...and so on... if member type is DGIL, then member id will be DGIL1, DGIL2, DGIL3 ...and so on...
So, how to write trigger for the same... I have tried as following but it is working for 1st record only.
ALTER TRIGGER [dbo].[next_member_id] ON [dbo].[DAD_MEMBERSHIP] AFTER INSERT
AS
BEGIN
DECLARE #COUNT INT
SET #COUNT=0;
SELECT #COUNT=ISNULL(MAX(CAST(SUBSTRING(DAD_MEMBERSHIP.MEMBER_ID,5,15) AS INT)),0)+1 FROM DAD_MEMBERSHIP where DAD_MEMBERSHIP.MEMBER_TYPE = DAD_MEMBERSHIP.MEMBER_TYPE
update DAD_MEMBERSHIP set DAD_MEMBERSHIP.MEMBER_ID = DAD_MEMBERSHIP.MEMBER_TYPE + CONVERT(varchar,#COUNT)
from DAD_MEMBERSHIP inner join inserted on DAD_MEMBERSHIP.MEMBER_TYPE = inserted.MEMBER_TYPE
END
Triggers operate by batch of records, you cannot assign to a scalar variable and expect it to work for more than one record. You need to rethink your whole process into a set-based process.
I solved the problem using following trigger
ALTER TRIGGER [dbo].[next_member_id]
ON [dbo].[DAD_MEMBERSHIP]
AFTER INSERT
AS
BEGIN
DECLARE #COUNT INT
SET #COUNT=0;
DECLARE #STR VARCHAR(5)
SET #STR=''
select #STR=i.MEMBER_TYPE from inserted i;
SELECT #COUNT=ISNULL(MAX(CAST(SUBSTRING(DAD_MEMBERSHIP.MEMBER_ID,5,15) AS INT)),0)+1
from DAD_MEMBERSHIP where MEMBER_TYPE=#STR
update DAD_MEMBERSHIP set DAD_MEMBERSHIP.MEMBER_ID = #STR + CONVERT(varchar,#COUNT)
from DAD_MEMBERSHIP inner join inserted i on i.MEMBER_TYPE=DAD_MEMBERSHIP.MEMBER_TYPE where DAD_MEMBERSHIP.MEMBER_ID is null
END