Hello I have the following stored procedure for MySQL but when it is executed in my ASP.NET Core application I get a Subquery returns more than 1 row error. What am I doing wrong here? The equivalent SQL Server version used to work without problems...
-- System Calculates Candidate’s Matching Score based on a Manager’s Answer Weights
CREATE PROCEDURE spSysCalcCandScore
(
IN Candidate_ID INT,
IN Manager_ID INT
)
Begin
DECLARE ansID INT;
DECLARE tempSum INT;
DECLARE Sum INT;
DECLARE Done INT DEFAULT FALSE;
DECLARE MyCursor CURSOR FOR
SELECT Answer_ID FROM Completed_Questionnaire
WHERE Candidate_ID = Candidate_ID;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET Done = TRUE;
START TRANSACTION;
OPEN MyCursor;
myloop: LOOP
FETCH MyCursor INTO ansID;
IF Done THEN
LEAVE myloop;
END IF;
SET tempSum = (SELECT Weight_Value FROM Weight WHERE (Answer_ID = ansID AND Manager_ID = Manager_ID));
SET Sum = Sum + tempSum;
END LOOP;
CLOSE MyCursor;
IF (Sum IS NULL) THEN
SET Sum = 0;
END IF;
UPDATE `Interest`
SET Matching_Score = Sum
WHERE (Candidate_ID = Candidate_ID AND Manager_ID = Manager_ID);
COMMIT;
End//
I have a stored procedure snippet like this
CREATE DEFINER=`root`#`%` PROCEDURE `new_procedure`()
BEGIN
DECLARE c_id varchar(100) DEFAULT "";
DECLARE cursor1 CURSOR for select id from t1 where name like 's%';
OPEN cursor1;
get_t1: LOOP
FETCH cursor1 into c_id;
p:begin
declare cursor2 cursor for select id from t2 where cl_id=c_id;
open cursor2;
get_t2: loop
fetch project_cursor into p_id;
// perform some tasks
t:begin
declare cursor3 cursor for select id from t3 where pr_id=p_id;
open cursor3;
get_t3:loop
fetch cursor3 into t_id;
IF v_finished = 1 THEN
LEAVE get_t3;
END IF;
//perform some tasks
close cursor3;
select p_id;
end t;
end loop t2;
end p;
END LOOP t1;
END
here select statement is not displaying any data
when i write select under cursor 3 it is working.
did i made any mistake? anything I missed
Some basic logic has been added in your SP, Try it whether this is what you are expecting.
CREATE DEFINER=`root`#`%` PROCEDURE `new_procedure`()
BEGIN
DECLARE c_id VARCHAR(100) DEFAULT "";
DECLARE done1 BOOLEAN DEFAULT FALSE;
DECLARE cursor1 CURSOR FOR SELECT id FROM t1 WHERE name LIKE 's%';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done1=TRUE;
OPEN cursor1;
GET_T1: LOOP
FETCH cursor1 INTO c_id;
IF done1 THEN
LEAVE GET_T1;
END IF;
P:BEGIN
DECLARE p_id INT ; -- check which data types suits you, might be int
DECLARE done2 BOOLEAN DEFAULT FALSE;
DECLARE cursor2 CURSOR FOR SELECT id FROM t2 WHERE cl_id=c_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2=TRUE;
OPEN cursor2;
GET_T2: LOOP
FETCH cursor2 INTO p_id;
IF done2 THEN
LEAVE GET_T2;
END IF;
/* perform some task */
T:BEGIN
DECLARE t_id INT ; -- check which data types suits you, might be int
DECLARE done3 BOOLEAN DEFAULT FALSE;
DECLARE cursor3 CURSOR FOR SELECT id FROM t3 WHERE pr_id=p_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done3=TRUE;
OPEN cursor3;
GET_T3:LOOP
FETCH cursor3 INTO t_id;
IF done3 THEN
LEAVE GET_T3;
END IF;
/* perform some tasks */
#select p_id; -- don't know what you are doing with this
END LOOP GET_T3;
CLOSE cursor3;
SET done3=FALSE;
END T;
END LOOP GET_T2;
CLOSE cursor2;
SET done2= FALSE;
END P;
END LOOP GET_T1;
CLOSE cursor1;
SET done1= FALSE;
END
I have this procedure which loops through article values, fetch tag1 and insert it into article_tag table:
DELIMITER $$
CREATE PROCEDURE dt1()
BEGIN
DECLARE maxid INT;
DECLARE x INT;
DECLARE t VARCHAR(30);
DECLARE ntag1 int;
SET maxid = (SELECT MAX(id) FROM `article`);
SET x = (SELECT MIN(id) FROM `article`) ;
WHILE x<= maxid DO
SET t = (SELECT tag1 from `article` WHERE id=x);
SET ntag1 = (SELECT count(*) from `article_tag` WHERE tag=t);
IF ntag1 = 0
THEN
INSERT INTO `article_tag` (tag, slug, frequency) VALUES (t, t, 1);
ELSE
UPDATE `article_tag` SET frequency = frequency + 1 WHERE tag=t;
END IF;
SET x = x + 1;
END WHILE;
END$$
This works fine when there are rows with id in the while loop, but when when there are some missing ids in between (like here)
I get
Query Error: Error: ER_BAD_NULL_ERROR: Column 'tag' cannot be null
I'm wondering what is the idiomatic way to deal with such missing rows?
You can use loop with cursor, so you will only loop through existing records and do not need to check for NULL.
Something like this:
DELIMITER \\
CREATE PROCEDURE dt1()
BEGIN
DECLARE t VARCHAR(30);
DECLARE done INT DEFAULT FALSE;
DECLARE cur1 CURSOR FOR SELECT tag FROM `article` ORDER BY id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
loop1: LOOP
FETCH cur1 INTO t;
IF done THEN
LEAVE loop1;
END IF;
SELECT COUNT(*) INTO #cnt from `article_tag` WHERE tag = t;
IF #cnt = 0 THEN
INSERT INTO `article_tag` (tag, slug, frequency) VALUES (t, t, 1);
ELSE
UPDATE `article_tag` SET frequency = frequency + 1 WHERE tag = t;
END IF;
END LOOP;
CLOSE cur1;
END
\\
DELIMITER ;
See manual for details:
https://dev.mysql.com/doc/refman/5.7/en/cursors.html
Sure, if possible I'd use INSERT ON DUPLICATE UPDATE as already mentioned.
Can anyone shed light on why this will not loop through the function and populate the temp table? Ive tried a number of things and at best can only get the first value to populate. I'm trying to take a value and a ":" separated string (queried in this procedure) to populate a table so I can reference it in a larger query. The function SPLIT_STR works great on its own but I cant seem to increment value "a" so that it separates ALL values per field per value.
BEGIN
DECLARE platform_val VARCHAR(255);
DECLARE productName_val VARCHAR(255);
DECLARE no_more_rows BOOLEAN;
DECLARE num_rows INT DEFAULT 0;
DECLARE loop_cntr INT DEFAULT 0;
DECLARE str VARCHAR(255);
DECLARE a INT DEFAULT 1;
DECLARE cur1 CURSOR FOR SELECT
ProductName,
ProductPlatforms
FROM Feed
limit 10;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
OPEN cur1;
select FOUND_ROWS() into num_rows;
the_loop: LOOP
FETCH cur1
INTO productName_val,
platform_val;
SET str = platform_val;
WHILE a< num_rows DO
SET str=SPLIT_STR(str,":",a);
insert into temp values (productName_val, str);
SET a=a+1;
END WHILE;
END LOOP the_loop;
END
This is the idea I came up with
CREATE PROCEDURE `col2lines`()
BEGIN
declare v_platform,v_productName,v_platformAll varchar(255) default null;
declare v_finished int default 0;
declare curs cursor for select ProductName,ProductPlatforms from Feed limit 10;
declare continue handler for not found set v_finished = 1;
drop temporary table if exists temp_table;
create temporary table temp_table (
productName varchar(255),
platform varchar(255)
);
open curs;
parent: LOOP
fetch curs into v_productName, v_platformAll;
if (v_finished = 1) then LEAVE parent; end if;
child: LOOP
set v_platform = substring_index(v_platformAll, '::', 1);
set #strlen = char_length(v_platform);
if (#strlen > 0) then
insert into temp_table values (v_productName, v_platform);
set v_platformAll = substr(v_platformAll, #strlen + 3);
iterate child;
end if;
LEAVE child;
END LOOP child;
iterate parent;
END LOOP parent;
close curs;
select * from temp_table;
END
Mysql cursor issue?
I have written a stored procedure which will travel's record from one table and insert those into 2-3 different tables
using insert statements.
Problem is that i am checking if record is not exists in table1 then I am inserting record from temptable to table1 ,table2 sequentially
,but the condition is having some problem i don't know it its always going into else part.
Code sample is as follows:
CREATE PROCEDURE `insertData`(In clientNo INT,In usedID INT)
BEGIN
declare mame varchar(100);
declare address varchar(100);
declare city varchar(50);
declare IdentityNO1 varchar(20)
declare cur1 cursor for select * from temptable;
declare continue handler for not found set done=1;
SET #clientNo = clientNO;
SET #userID = userID;
set done = 0;
open cur1;
igmLoop: loop
fetch cur1 into Name,Address,City,IdentityNO1,clientNo;
if done = 1 then leave igmLoop; end if;
//If no record exists in some records table1,table2.
IF ( (SELECT COUNT(*) FROM table1
WHERE IndentityNo=IdentityNo1
AND clientNo=#clientNo) < = 0)
INSERT INTO table1 (Name,IdentityNO) VALUES (name,IdentityNO1);
INSERT INTO table2 (Address,City) VALUES(address,city);
ELSE
INSERT INTO tblexceptional(Name,Address,City,IdentityNo)
VALUES(name,address,city,IdentityNo1);
end loop igmLoop;
close cur1;
END
There is no THEN nor END IF keywords, the procedure cannot compile.
Check this link for proper syntax of IF statement: http://dev.mysql.com/doc/refman/5.7/en/if.html
Use EXIST operator instead of (SELECT count(*)... ) <=0,
read this link to know the reason: http://sqlblog.com/blogs/andrew_kelly/archive/2007/12/15/exists-vs-count-the-battle-never-ends.aspx
IF EXISTS(
SELECT null FROM table1
WHERE IndentityNo=IdentityNo1
AND clientNo=#clientNo
)
THEN
INSERT INTO table1 (Name,IdentityNO) VALUES (name,IdentityNO1);
INSERT INTO table2 (Address,City) VALUES(address,city);
ELSE
INSERT INTO tblexceptional(Name,Address,City,IdentityNo)
VALUES(name,address,city,IdentityNo1);
END IF;
I recommend using some prefixes for procedure arguments and variable names to avoid ambiguity, for example use p_ for parameters and v_ for variables. It's hard to guess, looking at this code, which name is a column name, a variable or a procedure parameter. This can lead to mistakes and errors.
Avoid using SELECT * - this code will fail if someone will change the table structure. Explicitely list required columns in the cursor declaration:
declare cur1 cursor for
select name,Address,City,IdentityNO,clientNo
from temptable;
The corrected procedure might look like this:
CREATE PROCEDURE `insertData`(In p_clientNo INT,In p_usedID INT)
BEGIN
declare v_name varchar(100);
declare v_address varchar(100);
declare v_city varchar(50);
declare v_IdentityNO varchar(20)
declare v_clientNo int
declare cur1 cursor for
select name,Address,City,IdentityNO,clientNo
from temptable;
declare continue handler for not found set done=1;
set done = 0;
open cur1;
igmLoop: loop
fetch cur1 into v_name,v_Address,v_City,v_IdentityNO,v_clientNo;
if done = 1 then leave igmLoop; end if;
//If no record exists in some records table1,table2.
IF EXISTS( SELECT 1 FROM table1
WHERE IndentityNo = v_IdentityNo
AND clientNo = v_clientNo)
INSERT INTO table1 (Name,IdentityNO) VALUES (v_name,v_IdentityNO);
INSERT INTO table2 (Address,City) VALUES(v_address,v_city);
ELSE
INSERT INTO tblexceptional(Name,Address,City,IdentityNo)
VALUES(v_name,v_address,v_city,v_IdentityNo);
END IF;
end loop igmLoop;
close cur1;
END