Incorrect Output in mysql split function - mysql

I have created mysql function to split the string in rows using temporary table, it gives correct in temp table, but not when i call the function it returns 1 as output.
My code is as below
DELIMITER $$
DROP FUNCTION IF EXISTS `split`$$
CREATE FUNCTION `split`(`String` VARCHAR(8000), `Delimiter` CHAR(1)) RETURNS VARCHAR(8000) CHARSET latin1
BEGIN
DECLARE idx INT;
DECLARE slice VARCHAR(8000);
DECLARE result INT DEFAULT 0;
DROP TEMPORARY TABLE IF EXISTS tmp;
CREATE TEMPORARY TABLE `tmp` (items VARCHAR(8000));
-- set #tmptab = tmp;
SET idx = 1;
label: WHILE LENGTH(`String`)<1 OR `String` IS NULL DO
LEAVE label;
END WHILE;
loop_lable: WHILE (idx<>0) DO
SET idx = LOCATE(`Delimiter`,`String`);
IF (idx<>0) THEN
SET slice = LEFT(`String`,idx - 1);
ELSE
SET slice = `String`;
END IF;
IF(LENGTH(slice)>0) THEN
INSERT INTO tmp(Items) VALUES(slice) ;
SET result = 1;
END IF;
SET `String` = RIGHT(`String`,LENGTH(`String`) - idx);
IF LENGTH(`String`) = 0 THEN
LEAVE loop_lable;
END IF;
END WHILE;
RETURN result;
END$$
DELIMITER ;

Related

Using a custom(user-defined) function inside a procedure in 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.

Create temporary table inside a procedure

Here is the error I get when I try to run the code below.
I spent a day on mySQL tutorials + forums without any success.
DROP PROCEDURE IF EXISTS update_end_date_dwh_dimension_product;
delimiter $$
CREATE PROCEDURE update_end_date_dwh_dimension_product()
BEGIN
DROP TEMPORARY TABLE IF EXISTS __temp_BI__;
CREATE TEMPORARY TABLE __temp_BI__
SELECT dp.sku, dp.start_date
FROM dwh_dimension_product dp
ORDER BY dp.sku, dp.start_date;
DECLARE end_loop BOOLEAN DEFAULT TRUE;
DECLARE sku1_ VARCHAR(50);
DECLARE sku2_ VARCHAR(50);
DECLARE start_date1_ TIMESTAMP;
DECLARE start_date2_ TIMESTAMP;
DECLARE cursor_temp CURSOR
FOR select * from __temp_BI__;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_loop = FALSE;
OPEN cursor_temp;
FETCH cursor_temp INTO sku1_, start_date1_;
while_label: WHILE (end_loop) DO
IF end_loop = FALSE THEN
LEAVE while_label;
END IF;
FETCH cursor_temp INTO sku2_, start_date2_;
while_label2: WHILE (sku1_ = sku2_) DO
UPDATE dwh_dimension_product dp1
SET dp1.end_date = DATE_SUB(start_date2_, INTERVAL 1 SECOND)
WHERE dp1.sku = sku1_
AND dp1.start_date = start_date1_;
SET sku1_ = sku2_;
SET start_date1_ = start_date2_;
FETCH cursor_temp INTO sku2_, start_date2_;
IF end_loop = FALSE THEN
LEAVE while_label2;
END IF;
END WHILE;
UPDATE dwh_dimension_product dp2
SET dp2.end_date = NULL
WHERE dp2.sku = sku1_
AND dp2.start_date = start_date1_;
SET sku1_ = sku2_;
SET start_date1_ = start_date2_;
END WHILE;
CLOSE cursor_temp;
DROP TABLE IF EXISTS __temp_BI__;
END $$
delimiter ;
If I put this following code outside the procedure() it works
DROP TEMPORARY TABLE IF EXISTS __temp_BI__;
CREATE TEMPORARY TABLE __temp_BI__
SELECT dp.sku, dp.start_date
FROM dwh_dimension_product dp
ORDER BY dp.sku, dp.start_date;
Thank you for your advice.

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 ;

Compare String function in mysql by words

I am trying to create a search function in mysql. In order to make the search result more reliability i need to compare two string by words. Inputs are 2 strings and output is number word two strings match. In MySql i did as below.
CREATE DEFINER=`root`#`localhost` FUNCTION `CompareStrings`(str1 VARCHAR(255),str2 VARCHAR(255)) RETURNS double
BEGIN
DECLARE cur_position INT DEFAULT 1 ;
DECLARE remainder TEXT;
DECLARE cur_string VARCHAR(50);
DECLARE delimiter_length TINYINT UNSIGNED;
DECLARE numberMatch INT;
DECLARE total INT;
DECLARE result DOUBLE DEFAULT 0;
DECLARE delim VARCHAR(10);
DECLARE string2 VARCHAR(255);
SET delim = ' ';
DROP TEMPORARY TABLE IF EXISTS SplitString1;
CREATE TEMPORARY TABLE SplitString1 (
SplitString1ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT ,
val VARCHAR(50) NOT NULL
) ENGINE=MyISAM;
DROP TEMPORARY TABLE IF EXISTS SplitString2;
CREATE TEMPORARY TABLE SplitString2 (
SplitString1ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT ,
val VARCHAR(50) NOT NULL
) ENGINE=MyISAM;
SET remainder = str1;
SET delimiter_length = CHAR_LENGTH(delim);
WHILE CHAR_LENGTH(remainder) > 0 AND cur_position > 0 DO
SET cur_position = INSTR(remainder, delim);
IF cur_position = 0 THEN
SET cur_string = remainder;
ELSE
SET cur_string = LEFT(remainder, cur_position - 1);
END IF;
IF TRIM(cur_string) != '' THEN
INSERT INTO SplitString1(val) VALUES (cur_string);
END IF;
SET remainder = SUBSTRING(remainder, cur_position + delimiter_length);
END WHILE;
SET remainder = str2;
SET cur_position = 1;
WHILE CHAR_LENGTH(remainder) > 0 AND cur_position > 0 DO
SET cur_position = INSTR(remainder, delim);
IF cur_position = 0 THEN
SET cur_string = remainder;
ELSE
SET cur_string = LEFT(remainder, cur_position - 1);
END IF;
IF TRIM(cur_string) != '' THEN
INSERT INTO SplitString2(val) VALUES (cur_string);
END IF;
SET remainder = SUBSTRING(remainder, cur_position + delimiter_length);
END WHILE;
SELECT count(*) INTO numberMatch
FROM SplitString1 s1 JOIN SplitString2 s2 ON s1.val = s2.val;
RETURN result;
END
The idea is create two temporary table store each word and then compare these 2 tables. The result is good but the performace is awful. Anybody has better idea, please give me an advice.
Many thanks!
I don't think this will work as stated.
The logic is sound but you have not assigned any value to your result variable. Hence this function will always return 0. Replace:
RETURN result;
with
RETURN numberMatch;
Also replace:
CREATE DEFINER=`root`#`localhost` FUNCTION `CompareStrings`(str1 VARCHAR(255),str2 VARCHAR(255)) RETURNS double
with
CREATE DEFINER=`root`#`localhost` FUNCTION `CompareStrings`(str1 VARCHAR(255),str2 VARCHAR(255)) RETURNS double READS SQL DATA
As far as efficiency goes it looks pretty efficient. When you say 'performance is awful' - what constitutes 'awful'? Have you got any benchmark figures e.g. x calls took y millis?

For loop example in MySQL

In MySQL, I have this stored procedure with a LOOP:
DELIMITER $$
CREATE PROCEDURE ABC()
BEGIN
DECLARE a INT Default 0 ;
simple_loop: LOOP
SET a=a+1;
select a;
IF a=5 THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
END $$
It always prints 1. What is the correct syntax for a MySQL Loop?
drop table if exists foo;
create table foo
(
id int unsigned not null auto_increment primary key,
val smallint unsigned not null default 0
)
engine=innodb;
drop procedure if exists load_foo_test_data;
delimiter #
create procedure load_foo_test_data()
begin
declare v_max int unsigned default 1000;
declare v_counter int unsigned default 0;
truncate table foo;
start transaction;
while v_counter < v_max do
insert into foo (val) values ( floor(0 + (rand() * 65535)) );
set v_counter=v_counter+1;
end while;
commit;
end #
delimiter ;
call load_foo_test_data();
select * from foo order by id;
While loop syntax example in MySQL:
delimiter //
CREATE procedure yourdatabase.while_example()
wholeblock:BEGIN
declare str VARCHAR(255) default '';
declare x INT default 0;
SET x = 1;
WHILE x <= 5 DO
SET str = CONCAT(str,x,',');
SET x = x + 1;
END WHILE;
select str;
END//
Which prints:
mysql> call while_example();
+------------+
| str |
+------------+
| 1,2,3,4,5, |
+------------+
REPEAT loop syntax example in MySQL:
delimiter //
CREATE procedure yourdb.repeat_loop_example()
wholeblock:BEGIN
DECLARE x INT;
DECLARE str VARCHAR(255);
SET x = 5;
SET str = '';
REPEAT
SET str = CONCAT(str,x,',');
SET x = x - 1;
UNTIL x <= 0
END REPEAT;
SELECT str;
END//
Which prints:
mysql> call repeat_loop_example();
+------------+
| str |
+------------+
| 5,4,3,2,1, |
+------------+
FOR loop syntax example in MySQL:
delimiter //
CREATE procedure yourdatabase.for_loop_example()
wholeblock:BEGIN
DECLARE x INT;
DECLARE str VARCHAR(255);
SET x = -5;
SET str = '';
loop_label: LOOP
IF x > 0 THEN
LEAVE loop_label;
END IF;
SET str = CONCAT(str,x,',');
SET x = x + 1;
ITERATE loop_label;
END LOOP;
SELECT str;
END//
Which prints:
mysql> call for_loop_example();
+-------------------+
| str |
+-------------------+
| -5,-4,-3,-2,-1,0, |
+-------------------+
1 row in set (0.00 sec)
Do the tutorial: http://www.mysqltutorial.org/stored-procedures-loop.aspx
If I catch you pushing this kind of MySQL for-loop constructs into production, I'm going to shoot you with the foam missile launcher. You can use a pipe wrench to bang in a nail, but doing so makes you look silly.
Assume you have one table with name 'table1'. It contain one column 'col1' with varchar type. Query to crate table is give below
CREATE TABLE `table1` (
`col1` VARCHAR(50) NULL DEFAULT NULL
)
Now if you want to insert number from 1 to 50 in that table then use following stored procedure
DELIMITER $$
CREATE PROCEDURE ABC()
BEGIN
DECLARE a INT Default 1 ;
simple_loop: LOOP
insert into table1 values(a);
SET a=a+1;
IF a=51 THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
END $$
To call that stored procedure use
CALL `ABC`()
You can exchange this local variable for a global, it would be easier.
DROP PROCEDURE IF EXISTS ABC;
DELIMITER $$
CREATE PROCEDURE ABC()
BEGIN
SET #a = 0;
simple_loop: LOOP
SET #a=#a+1;
select #a;
IF #a=5 THEN
LEAVE simple_loop;
END IF;
END LOOP simple_loop;
END $$