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.
I have a database table which as below
I want to add each SoldD column to next row ValT column.
for example, query result for above given table should be like as
Above snapshot is for expected Results
so for, I have tried many things but failed to get expected results
Failed try 1:
SELECT *,(IFNULL((SELECT VaIT from saleorder s WHERE s.id > ss.id limit 1),0)+ss.SoldD) FROM `saleorder` ss
Failed try 2:
update saleorder SET SoldD=(IFNULL((SELECT VaIT from (SELECT * from saleorder WHERE id > id+1 limit 1) s),0)+SoldD)
Any help is highly appreciated, Thanks in advance!
MySql version:
CREATE DEFINER=`root`#`localhost` PROCEDURE `new_procedure`()
BEGIN
DECLARE id2 INT DEFAULT 0;
declare VALT2 INT DEFAULT 0;
declare soldD2 INT DEFAULT 0;
declare beforSo2 INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT Id, ValT, SoldD FROM saleorder ORDER BY id;
OPEN cur1;
FETCH cur1 INTO id2, VALT2, soldD2;
SET valT2 = soldD2;
x: LOOP
IF(valT2 IS NULL) THEN
SET valT2 = 0;
END IF;
IF(beforSo2 IS NULL) THEN
SET beforSo2 = 0;
END IF;
UPDATE saleorder
SET SoldD = beforSo2 + valT2
WHERE ID = id2;
SET beforSo2 = beforSo2 + valT2;
FETCH cur1 INTO id2, VALT2, soldD2;
END LOOP;
CLOSE cur1;
END
Then call procedure this way:
CALL new_procedure;
SqlServer version:
DECLARE db_cursor CURSOR FOR SELECT ID, ValT, SoldD FROM Table_2 ORDER BY ID;
DECLARE #ID INT;
DECLARE #valT INT;
DECLARE #soldD INT;
DECLARE #beforSoldD INT = 0;
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO #ID, #valT, #soldD;
SET #valT = #soldD;
WHILE ##FETCH_STATUS = 0
BEGIN
IF(#valT IS NULL)
SET #valT = 0;
IF(#beforSoldD IS NULL)
SET #beforSoldD = 0;
UPDATE Table_2
SET SoldD = #beforSoldD + #valT
WHERE ID = #ID;
SET #beforSoldD = #beforSoldD + #valT;
FETCH NEXT FROM db_cursor INTO #ID, #valT, #soldD;
END;
CLOSE db_cursor;
DEALLOCATE db_cursor;
Base data:
Result:
Actually I'm trying to insert some data into a table using a cursor, and I'm getting no error. It just says:
Query executed OK, 0 rows affected.
I'm trying to get data from each field of the testdatabase.wp_posts p table and insert it into an existing table `testdatabase.wp_postmeta.
My syntax is:
DROP PROCEDURE IF EXISTS add_authors_to_prod;
DELIMITER $$
CREATE PROCEDURE add_authors_to_prod()
BEGIN
DECLARE v_post_id INT;
DECLARE v_author_id INT;
DECLARE v_last_author INT DEFAULT 0;
DECLARE str VARCHAR(500);
DECLARE v_first_id INT DEFAULT 10916;
DECLARE author_csr CURSOR FOR
SELECT n.nid, p.id FROM testdatabase.wp_posts p
JOIN drupaltest.srmaif_field_data_field_auther_list auth ON auth.entity_id = p.id
JOIN drupaltest.node_field_data n ON auth.field_auther_list_nid = n.nid
ORDER BY p.id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_last_author = 1;
START TRANSACTION;
OPEN author_csr;
author_loop:LOOP
FETCH author_csr INTO v_author_id, v_post_id;
IF v_last_author THEN
SET str = CONCAT(str, '}');
LEAVE author_loop;
END IF;
IF v_first_id <> v_post_id THEN
SET v_first_id = v_post_id;
SET str = CONCAT(str, '}');
INSERT INTO testdatabase.wp_postmeta (post_id, meta_key, meta_value)
VALUES(v_post_id, 'authors', CONCAT(str, v_author_id));
SET str = 'a:2:{';
ELSE
SET str = CONCAT(str,'i:', v_author_id, ';s:5:\"', v_author_id, '\";');
END IF;
END LOOP author_loop;
CLOSE author_csr;
SET v_last_author=0;
END$$
DELIMITER ;
CALL add_authors_to_prod()
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
I Have a table somewhat like this:
rnumber
number = int, cod = int
SELECT * FROM number WHERE number = 21377 and cod = 55;
returns the correct value;
So i have a proc call to insert:
CREATE DEFINER=`root`#`%` PROCEDURE `create`(IN Numb INT, IN Cod INT, IN qt INT)
BEGIN
SET #Cont = 0;
SET #Init = Numb;
WHILE #Cont < qt DO
SET #Exist = (SELECT count(number) FROM rnumber WHERE number = #Init AND cod = Cod LIMIT 1);
IF #Exist = 0 THEN
INSERT INTO (...)
END IF;
SET #Cont = #Cont + 1;
SET #IniT = #Init + 1;
END WHILE;
END$$
CALL create (21377, 54, 1);
Always give me variable #Exist as 1, so no go on the if, even tho the combination of number and cod does not exists.
Can anyone point me what am i doing wrong?
Thank you.
Try using select into instead of set xx = (select...).
Also having cod = Cod will always return true...
You also need to declare your variables...
Try this one:
CREATE DEFINER=`root`#`%` PROCEDURE `create`(IN p_Numb INT, IN p_Cod INT, IN p_qt INT)
BEGIN
declare v_Exist integer;
declare v_Init integer;
declare v_Exist integer;
SET v_Cont = 0;
SET v_Exist = 0;
SET v_Init = p_Numb;
WHILE v_Cont < p_qt DO
SELECT count(number) into v_Exist FROM rnumber WHERE number = v_Init AND cod = p_Cod LIMIT 1;
IF v_Exist = 0 THEN
INSERT INTO (...)
END IF;
SET v_Cont = v_Cont +1;
SET v_IniT = v_Init + 1;
END WHILE;
END$$