Apparently fetch returns NULL - mysql

I am learning stored procedures, cursors in mysql and I stumble on it:
delimiter //
CREATE PROCEDURE some_func()
BEGIN
DECLARE link_rewrite VARCHAR(255);
DECLARE link_rewrite_cursor CURSOR FOR SELECT link_rewrite FROM prod;
OPEN link_rewrite_cursor;
SET #count = 0;
WHILE #count < 10 DO
FETCH link_rewrite_cursor INTO link_rewrite;
SELECT link_rewrite;
set #count = #count + 1;
END WHILE;
CLOSE link_rewrite_cursor;
END//
delimiter ;
My question is: Why SELECT link_rewrite always returns NULL (in prod table there is 9000 rows). SELECT link_rewrite FROM prod returns a lot of rows(9000 rows).

You should avoid using the same name for multiple different things. Specifically, give the variable a different name than the column you are selecting. For example, if you rename the variable v_link_rewrite then it will probably work:
delimiter //
DROP PROCEDURE IF EXISTS some_func //
CREATE PROCEDURE some_func()
BEGIN
DECLARE v_link_rewrite VARCHAR(255);
DECLARE link_rewrite_cursor CURSOR FOR SELECT link_rewrite FROM prod;
OPEN link_rewrite_cursor;
SET #count = 0;
WHILE #count < 10 DO
FETCH link_rewrite_cursor INTO v_link_rewrite;
SELECT v_link_rewrite;
set #count = #count + 1;
END WHILE;
CLOSE link_rewrite_cursor;
END//
delimiter ;

If you just want to select the top 10 rows, do this:
select link_rewrite from prod limit 10
It's much quicker and you don't have to go with a cursor.

Related

Running a query for each entry in a list of tables

I intend to write a procedure to run a query on each of the tables in a provided list (can be a comma separated list or a table - undecided on that yet)
I started off with creating a while loop to iterate through each element in the provided list. Have been able to extract each element but I don't know how to run a query for that extracted element/table.
DELIMITER $$
DROP PROCEDURE IF EXISTS retain_demo_clients$$
CREATE PROCEDURE retain_demo_clients()
BEGIN
DECLARE counter INT(10);
DECLARE client_tables VARCHAR(255);
DECLARE table_count INT(10);
DECLARE table_in_process VARCHAR(255);
SET counter = 1;
SET table_count = 3;
SET client_tables = 'client_table, somerandomstuff, somemorestuff';
WHILE (counter < table_count +1) DO
SET table_in_process = substring_index(substring_index(client_tables, ',',counter),',',-1);
SELECT table_in_process;
SET counter = counter +1;
END WHILE;
END$$
DELIMITER ;
CALL retain_demo_clients();
I expect to do something like 'select * from table_in_process'. Would also appreciate if there is a better way to loop through the list of tables.
Here is DBFiddle link, if someone wants to tinker: https://www.db-fiddle.com/f/v6EMsiWvXFrBoNLgoZwDVX/1
You can use EXECUTE to run a text that represent a single statement
SET #someQuery = CONCAT('SELECT * FROM ', table_in_process ) ;
PREPARE preparable_stmt FROM #someQuery;
EXECUTE preparable_stmt;

Looking for a solution for this IF statement in mySQL

I'm trying to create a IF statement with mySQL...
This is the if in Oracle SQL
CREATE OR REPLACE TRIGGER pruef
BEFORE INSERT ON belegung
FOR EACH ROW
DECLARE
counter_1 INTEGER;
beleg INTEGER;
max_platz INTEGER;
BEGIN
SELECT :new.kurs_id into beleg from dual;
SELECT COUNT (*) INTO counter_1 FROM belegung WHERE kurs_id = beleg;
SELECT max_personen INTO max_platz FROM KURS WHERE kurs_id = beleg;
IF counter_1 >= max_platz THEN
RAISE_APPLICATION_ERROR(-20101, 'Maximale Teilnehmerzahl überschritten');
END IF;
END;
/
And this is the mySQL Code
delimiter //
CREATE TRIGGER pruef_mysql
BEFORE INSERT ON BELEGUNG
FOR EACH ROW BEGIN
BEGIN
DECLARE 'counter_1' INT;
'beleg' INT;
'max_platz' INT;
SELECT new.kurs_id into 'beleg' FROM dual;
SELECT (*) INTO 'counter_1' FROM 'belegung' WHERE kurs_id=beleg;
SELECT 'max_personen' INTO 'max_platz' FROM 'KURS' WHERE kurs_id = beleg;
IF ('counter_1' >= 'max_platz', signal sqlstate -20101 set msgtext= 'Maximale Teilnehmerzahl überschritten');
END IF;
END//
DELIMITER ;
I don't know how I do this... Maybe searched on the wrong pages.
IF function and IF statement are two different things in MySQL
You want to use the later one
https://dev.mysql.com/doc/refman/8.0/en/if.html

Select into multiple varibales with 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

procedure, setting variable, repeat until, substring from one variable, mysql

I am looking for help with my sql procedure.
I would like to substring in loop each username, and alias from two input arguments and add it into table users. I have two procedures.
Sorry for Polish variable names and procedure names.
My first procedure is
CREATE DEFINER=`root`#`localhost` PROCEDURE `dodajZawodnika`(IN `dane` VARCHAR(50), IN `wyswietlanie` VARCHAR(50))
NO SQL
BEGIN
IF (SELECT 1 = 1 from zawodnicy where danezawodnika = dane AND dowyswietlenia=wyswietlanie) THEN
BEGIN
Select id from zawodnicy where danezawodnika=dane AND dowyswietlenia=wyswietlanie;
END;
ELSE
BEGIN
Insert INTO zawodnicy (danezawodnika, dowyswietlenia) VALUES(dane, wyswietlanie);
SELECT last_insert_id() AS ID;
END;
END IF;
END;
My second procedure is
CREATE DEFINER=`root`#`localhost` PROCEDURE `stworzSklad`(IN `dane` VARCHAR(1500), IN `pseudo` VARCHAR(1000))
NO SQL
BEGIN
DECLARE counter INTEGER;
DECLARE zawodnik VARCHAR(1500);
DECLARE pseudonim VARCHAR(1000);
DECLARE zawodnicy VARCHAR(1500);
DECLARE pseudonimy VARCHAR(1000);
DECLARE exit handler for sqlexception
BEGIN
-- ERROR
ROLLBACK;
END;
DECLARE exit handler for sqlwarning
BEGIN
-- WARNING
ROLLBACK;
END;
set counter = 0;
set #zawodnicy = dane;
set #pseudonimy = psuedo;
select #zawodnicy, #pseudonimy;
REPEAT
set zawodnik=(SELECT TRIM(SUBSTRING_INDEX(#zawodnicy, ',', 1)));
set pseudonim=(SELECT TRIM(SUBSTRING_INDEX(#pseudonimy, ',', 1)));
call dodajZawodnika(zawodnik, pseudonim);
SELECT RIGHT(#zawodnicy, TRIM(length(#zawodnicy) - length(SUBSTRING_INDEX(#zawodnicy, ',', 1)) - 1)) into #zawodnicy;
SELECT RIGHT(#pseudonimy, TRIM(length(#pseudonimy) - length(SUBSTRING_INDEX(#pseudonimy, ',', 1)) - 1)) into #pseudonimy;
select zawodnik as 'zawodnik', pseudonim as 'pseudonim', dane as 'dane', pseudo as 'pseudo', #zawodnicy as 'zawodnicy', #pseudonimy as 'pseudonimy';
set counter = counter + 1;
UNTIL (#zawodnicy = '' or counter = 30)
END REPEAT;
select counter;
END
I am fighting with it from about 2 hours.
I would like to use also transaction for this insert.
Please help me with this little problem.
How to make this in proper way?
Now, calling stworzSklad procedure make endless loop (ofc without counter in until condition) and any of user was not inserted in my table.
Cheers!

Find a column in one of many tables given only one value?

I have this:
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE column_name = 'whatever'
but what I need is something like this:
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE column_data = 'whatever'
So, in words, I have a value and I have no idea where it's stored. Is there a way to literally check the entire database and return the table, column?
aaaand yes, I know, db admins wouldn't be happy!
This might get you going in the right direction.
1. Create find_column stored procedure
DROP PROCEDURE IF EXISTS `find_column`;
DELIMITER $$
CREATE PROCEDURE `find_column`(IN i_value varchar(200),
OUT o_columns varchar(2000),
OUT o_message varchar(500))
MAIN_BLOCK : BEGIN
DECLARE is_numeric boolean;
CHECK_NUMERIC : BEGIN
set is_numeric = i_value REGEXP '^(-|\\+){0,1}([0-9]+\\.[0-9]*|[0-9]*\\.[0-9]+|[0-9]+)$';
END CHECK_NUMERIC;
FIND_IT : BEGIN
DECLARE bNoMoreRows BOOLEAN DEFAULT FALSE;
DECLARE v_schema varchar(64);
DECLARE v_table varchar(64);
DECLARE v_column varchar(64);
DECLARE v_data_type varchar(64);
DECLARE v_count int;
-- all schemas, tables and columns in DB
DECLARE columns CURSOR FOR
select table_schema,table_name,column_name,data_type from information_schema.columns;
DECLARE EXIT HANDLER for SQLEXCEPTION set o_message := concat('Unexpected error while trying to find schema, table and column for value : ',i_value);
declare continue handler for not found set bNoMoreRows := true;
open columns;
set o_columns = "";
COLUMN_LOOP: loop
fetch columns
into v_schema,v_table,v_column,v_data_type;
if (
(v_data_type in ('int','bigint','tinyint','decimal','smallint','mediumint') and is_numeric=1)
or (v_data_type not in ('int','bigint','tinyint','decimal','smallint','mediumint') and is_numeric=0)
)
then
SET #dyn_sql=CONCAT('select count(*) into #c from `',v_schema,'`.`',v_table,'` where `',v_column,'`=?');
SET #c = 0;
SET #v_value = i_value;
PREPARE stmt FROM #dyn_sql;
EXECUTE stmt using #v_value;
DEALLOCATE PREPARE stmt;
SET v_count = #c;
if v_count > 0 then
if length(o_columns <= 1800) then
set o_columns = concat(o_columns,",",v_schema,".",v_table,".",v_column);
end if;
end if;
end if;
if bNoMoreRows then
set o_columns = substring(o_columns,2);
close columns;
leave COLUMN_LOOP;
end if;
END loop COLUMN_LOOP;
END FIND_IT;
END MAIN_BLOCK$$
DELIMITER ;
2. Call find_column stored procedure with your value
call `find_column`('whatever',#columns,#message);
3. Check out the results
select #columns;
The is_numeric bit is lovingly ripped-off JBB's answer from this post.
It ain't perfect (what happens if the number of columns that your value exists exceeds 10 or so? If that is the case then this will only return the first 10 or so columns (depends on how long the schema.table.column name string is).
Hopefully it'll get you going in the correct direction.
An you're right. You're DB admins will be unhappy with you. But if you don't annoy them once in a while then you're not trying hard enough IMHO ;-)
Good luck.