Using a custom(user-defined) function inside a procedure in mysql - mysql

In the code below, there's a function that generates a random string, and a procedure that is supposed to insert random strings into a table called Users. I have successfully created the function and it's working without any problem, but when I try to create the procedure, it returns a syntax error at line "SET #str = SELECT randstring(8);" I think I am trying to call my function in a wrong way. I'm new to databases so please bear with me.
DELIMITER $$
CREATE FUNCTION `Randstring`(LENGTH SMALLINT(3)) RETURNS VARCHAR(100) CHARSET utf8
BEGIN
SET #returnStr='';
SET #allowedChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
SET #i = 0;
WHILE (#i < LENGTH) DO
SET #returnStr = CONCAT(#returnStr, SUBSTRING(#allowedChars, FLOOR(RAND() * LENGTH(#allowedChars) + 1), 1));
SET #i = #i + 1;
END WHILE;
RETURN #returnStr;
END
DELIMITER $$
CREATE PROCEDURE insertdata()
BEGIN
SET #str='';
DECLARE i INT DEFAULT 0;
WHILE i <= 1000 DO
SET #str = SELECT randstring(8);
INSERT INTO Users (user_name)
VALUES(#str);
SET i = i + 1;
END WHILE;
END $$
DELIMITER ;

Presumably, you intend either:
SET #str = randstring(8);
Or:
SELECT #str := randstring(8);
Or:
SET #str = (SELECT #randstring(8));
A SELECT when used as a subquery needs a parentheses before it. However, no subquery is really necessary.

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;

Store Procedure Concat a select while in a loop

I'm building a serie of Procedures where I'll have to insert generic names in almost all of them, and multiples columns.
So I thought in create a Procedure to Generate a "text" for me. The code for the text is this:
SELECT CONCAT( CHAR( FLOOR(65 + (RAND() * 25))));
This generates one random char for me. So this is the procedure that I made:
DELIMITER ;;
CREATE DEFINER=`my_definer`#`localhost` PROCEDURE GenericName(IN NumRows INT,OUT retorno VARCHAR)
BEGIN
DECLARE i INT;
SET i = 1;
SET retorno = "";
WHILE i <= NumRows DO
SET retorno = SELECT CONCAT( CHAR( FLOOR(65 + (RAND() * 25))));
SET i = i + 1;
END WHILE;
END;;
DELIMITER ;
The following error is what is appearing when I try to create the procedure:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near ') BEGIN DECLARE i INT; SET i = 1; SET retorno = "";
Based on the error, I think is something stupid, but I don't have much of expertise in creating Store Procedures and I may be overthinking something.
PS (this is the future usage that I'm planing to do when I finish the procedure above): The idea is to call this procedure in other procedures by something like:
INSERT INTO tbl_a (name, position) VALUES (CALL GenericName(7), CALL GenericName(5));
External links:
I saw that is possible to call a procedure from another procedure here "Calling a Stored Procedure in a Stored Procedure in MySQL"
PROBLEM #1
You should not be using a Stored Procedure. You should be using a Stored Function
PROBLEM #2
In the loop, you forgot to include retorno in the CONCAT
PROBLEM #3
Also, I would change
CHAR(FLOOR(65 + (RAND() * 25)))
to
CHAR(FLOOR(65.5 + (RAND() * 25)))
to give the letter Z a fair chance to appear
PROBLEM #4
Replace
SET retorno = SELECT CONCAT(...
with
SET retorno = CONCAT(...
PROPOSED STORED FUNCTION
DELIMITER ;;
CREATE DEFINER=`my_definer`#`localhost` FUNCTION GenericName
(NumRows INT)
RETURNS VARCHAR(20)
DETERMINISTIC
BEGIN
DECLARE i INT;
DECLARE retorno VARCHAR(20);
SET i = 1;
SET retorno = "";
WHILE i <= NumRows DO
SET retorno = CONCAT(retorno,CHAR(FLOOR(65.5 + (RAND() * 25))));
SET i = i + 1;
END WHILE;
RETURN retorno;
END;;
DELIMITER ;
Then, you can call the INSERT like this
INSERT INTO tbl_a (name, position) VALUES (GenericName(7),GenericName(5));
GIVE IT A TRY !!!

Mysql - How to split text variable in stored procedure

I have a MySQL variable as below.
DECLARE str TEXT DEFAULT '2014-01-02 13:00:00|2014-02-04 12:59:59#0#2014-02-04 13:00:00|2014-03-04 12:59:59#0#2014-03-04 13:00:00|2014-04-02 13:59:59#0#2014-04-02 14:00:00|2014-05-02 14:59:59#0#2014-05-02 15:00:00|2014-06-03 14:59:59';
I want to break this whole string first by using the separator #0# and from the results break the string using separator |.
I have tried MySQL split_str function but I am not able to do it.
Its giving me the error split_str does not exist.
Please suggest some other way to do this.
Finally i have resolved my problem using below procedure.
I am able to solve it using temporary table and procedure. I am no more using mysql variable for this. We can call the procedure as below....
CALL SplitString('2014-01-02 13:00:00|2014-02-04 12:59:59#0#2014-02-04 13:00:00|2014-03-04 12:59:59#0#2014-03-04 13:00:00|2014-04-02 13:59:59#0#2014-04-02 14:00:00|2014-05-02 14:59:59#0#2014-05-02 15:00:00|2014-06-03 14:59:59', '#0#', 'tblindex');
Here tblindex is temporary table i have used.
My procedure is below....
DELIMITER $$
DROP PROCEDURE IF EXISTS `SplitString`$$
CREATE PROCEDURE `SplitString`( IN input TEXT,IN delm VARCHAR(10),tblnm varchar(50))
BEGIN
DECLARE cur_position INT DEFAULT 1 ;
DECLARE remainder TEXT;
DECLARE cur_string VARCHAR(1000);
DECLARE delm_length TINYINT UNSIGNED;
set #sql_drop = concat("DROP TABLE IF EXISTS ",tblnm);
prepare st_drop from #sql_drop;
execute st_drop;
set #sql_create = concat("CREATE TEMPORARY TABLE ",tblnm," (value VARCHAR(2000) NOT NULL ) ENGINE=MEMORY;");
prepare st_create from #sql_create;
execute st_create;
SET remainder = input;
SET delm_length = CHAR_LENGTH(delm);
WHILE CHAR_LENGTH(remainder) > 0 AND cur_position > 0
DO
SET cur_position = INSTR(remainder, delm);
IF cur_position = 0 THEN
SET cur_string = remainder;
ELSE
SET cur_string = LEFT(remainder, cur_position - 1);
END IF;
-- select cur_string;
IF TRIM(cur_string) != '' THEN
set #sql_insert = concat("INSERT INTO ",tblnm," VALUES ('",cur_string,"');");
prepare st_insert from #sql_insert;
execute st_insert;
END IF;
SET remainder = SUBSTRING(remainder, cur_position + delm_length);
END WHILE;
END$$
DELIMITER ;

Simple MySQL function error

I'm trying to write a MySQL function which returns whether an username is in my table or not. It's the following:
CREATE FUNCTION UserExists (pUserName VARCHAR(40))
RETURNS BIT DETERMINISTIC
BEGIN
DECLARE rVal BIT;
IF EXISTS (SELECT * FROM Users WHERE userName = pUserName)
THEN SET rVal = 1;
ELSE SET rVal = 0;
END IF;
RETURN rVal;
END;
However, I get an error. Any ideas?
try this
IF(EXISTS(SELECT * FROM Users WHERE userName = pUserName))
how about using user define variable?
DELIMITER $$
CREATE FUNCTION UserExists (pUserName VARCHAR(40))
RETURNS BIT DETERMINISTIC
BEGIN
DECLARE rVal BIT;
SET #recCount := (SELECT COUNT(*) FROM Users WHERE userName = pUserName);
IF #recCount > 0 THEN
SET rVal = 1;
ELSE
SET rVal = 0;
END IF;
RETURN rVal;
END $$
DELIMITER ;
Before you query your mysql database, you need to use %mysql sudo -u -p and then give your commands.

Apparently fetch returns NULL

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.