Select into multiple varibales with MySQL - mysql

I need to write a stored procedure using mysql.
In the repeat loop showing below, if I use something as:
SET VDATEI=(SELECT A.DATEI FROM STAFF_CONVENIOS A WHERE
A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1);
the stored procedure works well and I get a result set.
But, I need select into multiple variables. Something as:
SELECT
A.DATEI, A.DIAI, A.HORAI
INTO
VDATEI, VDIAI, VHORAI
FROM
STAFF_CONVENIOS A
WHERE
A.CONV_ID = CONVE AND A.STAFF_ID = MED
LIMIT 1;
In this case my stored procedure is broken I get no result set.
How to use select into to multiple variables into stored procedure with temporary tables?
My stored procedure is similar to:
CREATE PROCEDURE P_GETHORARIOS(
IN `MED` BIGINT,
IN `DATAREF` DATE,
IN `ESPEC` BIGINT,
IN `CONVE` BIGINT
)
BEGIN
DECLARE BDONE,BTEMP, BOCUP INT;
DECLARE DIA;
DECLARE VDIA,OK TINYINT;
DECLARE VDURACAO TINYINT;
DECLARE VDATEI DATE;
DECLARE VDIAI TINYINT;
DECLARE VHORAI TIME;
DECLARE VHORA, VHORAI,VHORAF TIME;
DECLARE CURS CURSOR FOR SELECT DIA,COALESCE(A.DURACAO,30) AS DURACAO, A.HINI FROM STAFF_ESCALA A
WHERE A.DIA=DIA;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET BDONE = 1;
DROP TEMPORARY TABLE IF EXISTS TBLRESULTS;
CREATE TEMPORARY TABLE IF NOT EXISTS TBLRESULTS (
DATA_AG DATE,
DIA TINYINT,
HORA TIME );
SET DIA=DAYOFWEEK(DATAREF);
OPEN CURS;
SET BDONE = 0;
REPEAT
SET OK=TRUE;
FETCH CURS INTO VDIA,VDURACAO,VHORAI;
-- SET VDATEI=(SELECT A.DATEI FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1);
SELECT A.DATEI, A.DIAI,A.HORAI INTO VDATEI, VDIAI,VHORAI FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1;
SET BTEMP=IF(VDATEI IS NULL,TRUE,FALSE);
SET OK=OK AND BTEMP ;
IF (OK) THEN
INSERT INTO TBLRESULTS VALUES (DATAREF,VDIA,VHORA);
ELSE INSERT INTO TBLRESULTS VALUES (VDATEI,VDIAI,VHORAI);
END IF;
UNTIL BDONE END REPEAT;
CLOSE CURS;
SELECT A.* FROM TBLRESULTS;
END
I have posted a sample of my problem. Here is the real stored procedure:
CREATE DEFINER=`SYSDBA`#`%` PROCEDURE `P_GETHORARIOS`(
IN `MED` BIGINT,
IN `DATAREF` DATE,
IN `ESPEC` BIGINT,
IN `CONVE` BIGINT
)
LANGUAGE SQL
NOT DETERMINISTIC
MODIFIES SQL DATA
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE BDONE INT;
DECLARE BTEMP TINYINT;
DECLARE BOCUP TINYINT;
DECLARE DIA BIGINT;
DECLARE VDIA TINYINT;
DECLARE VDURACAO TINYINT;
DECLARE VHORA, VHORAI,VHORAF TIME;
DECLARE VMED_ID BIGINT;
DECLARE VESPEC_ID BIGINT;
DECLARE VCONV_ID BIGINT;
DECLARE OK TINYINT;
DECLARE VNOMEESPEC,VNOMEMED VARCHAR(100);
DECLARE CURS CURSOR FOR SELECT DIA,COALESCE(A.DURACAO,30) AS DURACAO, A.HINI, A.HFIM, A.STAFF_ID,B.NOME AS NOMESTAFF, A.ESPEC_ID,C.NOME AS NOMEESPEC
FROM STAFF_ESCALA A
LEFT JOIN STAFF B ON B.ID=A.STAFF_ID
LEFT JOIN ESPECIALIDADES C ON C.ID=A.ESPEC_ID
WHERE A.DIA=DIA;
-- DECLARE CURS CURSOR FOR SELECT HINI, HFIM FROM STAFF_ESCALA;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET BDONE = 1;
DROP TEMPORARY TABLE IF EXISTS TBLRESULTS;
CREATE TEMPORARY TABLE IF NOT EXISTS TBLRESULTS (
DATA_AG DATE,
DIA TINYINT,
HORA TIME,
MED_ID BIGINT,
NOME_MED VARCHAR(100),
ESPEC_ID BIGINT,
NOME_ESPEC VARCHAR(100)
);
SET DIA=DAYOFWEEK(DATAREF);
OPEN CURS;
SET BDONE = 0;
REPEAT
SET OK=TRUE;
FETCH CURS INTO VDIA,VDURACAO,VHORAI,VHORAF,VMED_ID,VNOMEMED,VESPEC_ID,VNOMEESPEC;
IF (MED IS NOT NULL) THEN
SET OK=IF(MED=VMED_ID,TRUE,FALSE) ;
END IF;
IF (ESPEC IS NOT NULL) THEN
SET OK=OK AND IF(ESPEC=VESPEC_ID,TRUE,FALSE) ;
END IF;
IF (CONVE IS NOT NULL) THEN
-- SET #EOK=(SELECT 1 FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1);
SELECT 1 INTO #EOK FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1;
SET BTEMP=IF(#EOK IS NULL,TRUE,FALSE);
SET OK= OK AND BTEMP ;
END IF;
IF (OK) THEN
SET VHORA=VHORAI;
IF (VDURACAO IS NULL) THEN
SET VDURACAO=30;
END IF;
WHILE (VHORA <= VHORAF) DO
SET BOCUP=(SELECT 1 FROM AGENDA_STAFF A WHERE A.DATA_MARCADA=DATAREF AND A.HORA_MARCADA=VHORA);
IF (BOCUP IS NULL) THEN
INSERT INTO TBLRESULTS VALUES (DATAREF,VDIA,VHORA,VMED_ID,VNOMEMED,VESPEC_ID,VNOMEESPEC);
END IF;
SET VHORA=ADDTIME(VHORA, VDURACAO * 100);
END WHILE;
SET VHORA=ADDTIME(VHORA, VDURACAO * (-100));
IF (VHORA < VHORAF) THEN
SET VHORA=VHORAF;
SET BOCUP=(SELECT 1 FROM AGENDA_STAFF A WHERE A.DATA_MARCADA=DATAREF AND A.HORA_MARCADA=VHORA);
IF (BOCUP IS NULL) THEN
INSERT INTO TBLRESULTS VALUES (DATAREF,VDIA,VHORA,VMED_ID,VNOMEMED,VESPEC_ID,VNOMEESPEC);
END IF;
END IF;
END IF;
UNTIL BDONE END REPEAT;
CLOSE CURS;
SELECT A.* FROM TBLRESULTS A LEFT JOIN AGENDA_STAFF B ON B.STAFF_ID=A.MED_ID AND B.HORA_MARCADA=A.HORA AND B.DATA_MARCADA=A.DATA_AG;
END
//
The problem is with the lines:
-- SET #EOK=(SELECT 1 FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1);
SELECT 1 INTO #EOK FROM STAFF_CONVENIOS A WHERE A.CONV_ID=CONVE AND A.STAFF_ID=MED LIMIT 1;
If I use "SET #EOK..." all works well.
If I use SELECT 1 INTO #EOK.. the problem appears.
More info with data
Expected result from call p_gethorarios(7,'2017-11-20',47,21)
"data_ag";"dia";"hora";"med_id";"nome_med";"espec_id";"nome_espec"
"2017-11-20";"2";"08:30:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"09:00:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"09:30:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"10:00:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"08:30:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"09:00:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"09:30:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
"2017-11-20";"2";"10:00:00";"7";"Paulo Renato Scofano";"47";"Pediatria/Neonatologia"
STAFF-ESCALA TABLE
ID;STAFF_ID;DIA;HINI;HFIM;ESPEC_ID;DURACAO;CREATION_TIME;MODIFICATION_TIME;LAST_USER_MODIF
25;7;2;08:00:00;10:00:00;50;;18/11/2017 21:44:02;;1
26;7;6;08:00:00;10:00:00;50;;18/11/2017 21:55:27;;1
27;7;4;08:00:00;10:00:00;50;;18/11/2017 21:55:27;;1
28;7;5;08:00:00;10:00:00;50;;18/11/2017 21:56:36;;1
35;7;3;08:00:00;10:00:00;47;;19/11/2017 19:10:29;;1
36;7;5;08:00:00;10:00:00;47;;19/11/2017 19:10:29;;1
38;7;2;08:00:00;10:00:00;47;;19/11/2017 19:10:29;;1

You may have to use user/session variables (the #xyz kind). The documentation does not explicitly state such, but it only shows examples with them.
https://dev.mysql.com/doc/refman/5.7/en/select-into.html
If it is an issue with the NOT FOUND handler getting triggered from something other than the cursor, you could try structuring your code something like this (very pseudocode):
FETCH
WHILE( NOT DONE )
BEGIN
DO STUFF
SET DONE = FALSE
FETCH
END

Related

MySqlException: Subquery returns more than 1 row, for a stored procedure with a cursor

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//

Cursor with JOIN and WHERE MySQL

I am trying to create a repetition in 'cursor' that uses 'join', but it doesn't work.
Already tested without 'join' and works normally.
My code:
DECLARE hvDataAtual DATE;
DECLARE manDataAtual DATETIME;
DECLARE motCodAtual INT;
DECLARE done INT DEFAULT FALSE;
DECLARE Crs_vei_man
CURSOR FOR (
SELECT hvedatageracao, hvedatageracao, hvemotorista
FROM tableone INNER JOIN tabletwo ON hveveiculo = manveiculo
WHERE SUBSTRING(mandata, 1, 10) = SUBSTRING(hvedatageracao, 1, 10) LIMIT 10);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN Crs_vei_man;
myloop: LOOP
FETCH Crs_vei_man
INTO hvDataAtual,
manDataAtual,
motCodAtual;
-- Insert 1 row (null, null, null) ?
INSERT INTO testes VALUES(hvDataAtual, manDataAtual, motCodAtual);
IF done THEN
LEAVE myloop;
END IF;
IF motCodAtual > 0 THEN
INSERT INTO testes VALUES('hvDataAtual', 'manDataAtual', 'motCodAtual');
END IF;
END LOOP;
CLOSE Crs_vei_man;
This code is in a stored procedure.
What is happening?

Mysql Store procedure stops iteration after some rows

Below procedure code running with out error . Line select FOUND_ROWS() returning n no. rows but cursor curs did not loop all rows
CREATE DEFINER=`root`#`%` PROCEDURE `middleLocationAutoUpdatePorc`()
BEGIN
declare vname varchar(45);
declare vmobile varchar(20);
declare vsapid varchar(6);
declare vuser varchar(45);
declare vday date;
declare vmintime time;
declare vmaxtime time;
declare vminLocation mediumtext;
declare vmaxLocation mediumtext;
declare vmiddlelocation mediumtext;
declare vdistance int(11);
declare vdrdid int(11);
declare vn_no_details int(11);
declare uatt varchar(45) default 'X';
declare adatta varchar(45) default 'X';
declare b_not_found BOOL DEFAULT FALSE;
declare curs CURSOR FOR
SELECT user ,day, mintime,maxtime_mobile,minLocation,maxLocation,distance,n_no_details,drdid FROM mydb.statusreport where day >= '2017-06-26';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET b_not_found = true;
OPEN curs;
loop1: LOOP
FETCH curs INTO vuser,vday,vmintime,vmaxtime,vminLocation,vmaxLocation,vdistance,vn_no_details,vdrdid;
IF b_not_found THEN
LEAVE loop1;
END IF;
-- select FOUND_ROWS();
case substring_index(vuser,"-",-1)
when 'RSM' then
select username,Name,mobile into vsapid,vname,vmobile from mydb.supervisor where idSu=CONVERT(substring_index(vuser,"-",1),UNSIGNED INTEGER);
when 'ASM' then
select userName,name,mobile into vsapid,vname,vmobile from mydb.executive where exeid=CONVERT(substring_index(vuser,"-",1),UNSIGNED INTEGER);
when 'F' then
select sapId,name,phone into vsapid,vname,vmobile from mydb.user where idUser=CONVERT(substring_index(vuser,"-",1),UNSIGNED INTEGER);
end case;
select userGiven , adminGiven into uatt ,adatta from userdaystatus st where st.date =vday and st.idUser=CONVERT(substring_index(vuser,"-",1),UNSIGNED INTEGER) and st.userType=substring_index(vuser,"-",-1);
set vmiddlelocation=( select location from mydb.dailyReportDetails as dtb where dtb.idDailyReport=vdrdid and dtb.counter>=(abs(vn_no_details/2) ) order by dtb.idDailyReportDetails asc limit 1);
call mydb.addOMiddleLocation(day(vday), month(vday),
year(vday),vuser, vname,
vsapid, vmobile, vmintime,
vmaxtime, SUBTIME(vmaxtime,vmintime),
vminLocation,
vmiddlelocation,
vmaxLocation,Round(vdistance/1000,2),
uatt, adatta);
END LOOP;
CLOSE curs;
END
The Procedure call mydb.addOMiddleLocation() just inserting Row on another table.There does not have any data type validation .
So what can be the problem ?
It happen for log wait time for a particular Query line
set vmiddlelocation=( select location from mydb.dailyReportDetails as dtb where dtb.idDailyReport=vdrdid and dtb.counter>=(abs(vn_no_details/2) ) order by dtb.idDailyReportDetails asc limit 1);

Using for loop in MySql data set

How to use for loop in MySQL data set ?
FOR x IN (SELECT column FROM table_name WHERE column_2 = input_val)
LOOP
sum_total := sum_total + x.column ;
END LOOP;
This is an example how I used to loop data set in oracle.
How can this be achieved in MySql ?
How about not looping at all. It's SQL after all.
SELECT SUM(`column`) total
FROM table_name
WHERE column_2 = <input_val>
Otherwise use CURSOR
Now, equivalent loop using CURSOR will look like
DELIMITER $$
CREATE PROCEDURE sp_loop(IN input_val INT)
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE sum_current, sum_total INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT column1 FROM table_name WHERE column2 = input_val;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO sum_current;
IF done THEN
LEAVE read_loop;
END IF;
SET sum_total = sum_total + sum_current;
END LOOP;
CLOSE cur1;
SELECT sum_total;
END$$
DELIMITER ;
Here is SQLFiddle
DROP PROCEDURE IF EXISTS `foo`.`usp_cursor_example`;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `foo`.`usp_cursor_example`(
IN name_in VARCHAR(255)
)
READS SQL DATA
BEGIN
DECLARE name_val VARCHAR(255);
DECLARE status_update_val VARCHAR(255);
-- Declare variables used just for cursor and loop control
DECLARE no_more_rows BOOLEAN;
DECLARE loop_cntr INT DEFAULT 0;
DECLARE num_rows INT DEFAULT 0;
-- Declare the cursor
DECLARE friends_cur CURSOR FOR
SELECT
name
, status_update
FROM foo.friend_status
WHERE name = name_in;
-- Declare 'handlers' for exceptions
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET no_more_rows = TRUE;
OPEN friends_cur;
select FOUND_ROWS() into num_rows;
the_loop: LOOP
FETCH friends_cur
INTO name_val
, status_update_val;
IF no_more_rows THEN
CLOSE friends_cur;
LEAVE the_loop;
END IF;
select name_val, status_update_val;
-- count the number of times looped
SET loop_cntr = loop_cntr + 1;
END LOOP the_loop;
-- 'print' the output so we can see they are the same
select num_rows, loop_cntr;
END
DELIMITER ;

Dynamic Views in Mysql Stored Procedure does not update

I have a table containing 100,000+ records from which i have some calculations to do based on a value which is stored in a specific column.
For this i have written a stored procedure which takes 100 rows at a time from the base table. Since cursors don't support dynamic sql. What i did was i create a dynamic view and the cursor always selects data from that view.
The code :
BEGIN
-- VARIABLES TO RETURN
DECLARE ORIG_COUNT INT ;
DECLARE SERVED_COUNT INT;
-- VARIABLED FOR LOOPING
DECLARE no_more_rows BOOLEAN;
DECLARE no_more_rows_sub BOOLEAN;
DECLARE num_rows INT DEFAULT 0;
SET #ORIG_COUNT =0;
SET #SERVED_COUNT=0;
SELECT COUNT(*) FROM table_one AS A WHERE A.year='2011' INTO #ORIG_COUNT ;
DELETE FROM table_test;
insert into table_test values ('Total Rows',#ORIG_COUNT,NULL);
DROP TABLE IF EXISTS table_request;
CREATE TABLE table_request (
BN_NUM VARCHAR(25) NOT NULL,
DN_NUM varchar(10) NOT NULL,
A_TOTAL FLOAT DEFAULT 0,
B_TOTAL FLOAT DEFAULT 0,
C_TOTAL FLOAT DEFAULT 0,
PRIMARY KEY (BN)
);
WHILE (#SERVED_COUNT<#ORIG_COUNT) DO
DROP VIEW IF EXISTS pbs_history.temp_view;
SET #query = CONCAT('CREATE VIEW temp_view as SELECT A.BN,A.DN
FROM table_one AS A
WHERE A.year='2011'
ORDER BY A.ID
LIMIT ', #SERVED_COUNT,',100');
PREPARE stmt from #query;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
/* ================= HERE ==================== */
SELECT * FROM temp_view;
BLOKA:BEGIN
DECLARE BN VARCHAR(25);
DECLARE DN VARCHAR(10);
DECLARE num_rows INT(5) DEFAULT 0;
DECLARE bn_count INT(5) DEFAULT 0;
DECLARE sel_recs CURSOR FOR SELECT * FROM temp_view;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
insert into table_test values('Start Served',#SERVED_COUNT,#query);
OPEN sel_recs;
SELECT FOUND_ROWS() INTO #num_rows;
insert into table_test values('Found Rows in View',#num_rows,NULL);
the_loop: LOOP
FETCH sel_recs INTO BN,DN;
IF no_more_rows THEN
CLOSE sel_recs;
LEAVE the_loop;
END IF;
SET #bn_count=0;
SELECT COUNT(*) FROM table_request WHERE BILL_NUMBER=BN INTO #bn_count;
insert into table_test VALUES(BN,DN,#bn_count);
IF(#bn_count=0) THEN
INSERT INTO table_request VALUES (BN,DN,0,0,0);
END IF;
BLOKB:BEGIN
DECLARE CAT VARCHAR(5);
DECLARE T1 FLOAT;
DECLARE data_fetch CURSOR FOR SELECT CAT_ID, TYPE_1 FROM transactions WHERE ID=BN;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows_sub = TRUE;
OPEN data_fetch;
sub_loop: LOOP
FETCH data_fetch INTO CAT,T1;
IF no_more_rows_sub THEN
CLOSE data_fetch;
LEAVE sub_loop;
END IF;
IF (CAT='P1') THEN
UPDATE table_request SET A_TOTAL = A_TOTAL+T1 WHERE BN_NUM=BN;
ELSEIF (CAT='P2') THEN
UPDATE table_request SET B_TOTAL = B_TOTAL+T1 WHERE BN_NUM=BN;
ELSEIF (CAT='P3') THEN
UPDATE table_request SET N_TOTAL = N_TOTAL+T1 WHERE BN_NUM=BN;
END IF;
END LOOP sub_loop;
END BLOKB;
SET #SERVED_COUNT = #SERVED_COUNT+1;
END LOOP the_loop;
insert into table_test values ('End the_loop',0,NULL);
END BLOKA;
END WHILE;
END
I'm testing the code with a subset from the original table. And the subset has 461 records.
And with this code there should be 5 iterations. And in the final iteration the view should contain only 61 records. But with this code each iteration has 100 records, and during each iteration it takes into consideration only the first 100 records.
But if i run SELECT * FROM temp_view in mysql console after the procedure has run, it shows the last 61 records.
Anybody can point out what i'm doing wrong here?