I'm on developing web project and i get some problem with migration from oracle database to mysql database. I want to create function with this code :
DROP FUNCTION IF EXISTS F_MANIFEST_GABUNG_SMR;
DELIMITER //
CREATE FUNCTION F_MANIFEST_GABUNG_SMR (input_val varchar(4000))
RETURNS VARCHAR(4000)
BEGIN
DECLARE return_text VARCHAR(10000) DEFAULT NULL;
DECLARE not_found INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET not_found = 1;
DECLARE x CURSOR FOR SELECT DISTINCT IFNULL(SMR,'-') SMR FROM MANIFEST_EDI_SMR WHERE BL_NBR = input_val; OPEN x;
FETCH x INTO;
WHILE NOT_FOUND=0
DO
SET return_text = concat(ifnull(return_text, '') , ' ' , IFNULL(x.SMR, '')) ;
FETCH INTO;
END WHILE;
CLOSE ;
IF char_length(return_text) > 85 THEN
SET return_text = concat(ifnull(substr(return_text,1,85), '') , ' detail asp BL');
END IF;
RETURN return_text;
END;
//
DELIMITER ;
I am using phpmyadmin to store function with routine. Thanks for your help :)
The error message is self explanatory:you have declare the cursor after handler,need to change the order:
DROP FUNCTION IF EXISTS F_MANIFEST_GABUNG_SMR;
DELIMITER //
CREATE FUNCTION F_MANIFEST_GABUNG_SMR (input_val varchar(4000))
RETURNS VARCHAR(4000)
BEGIN
DECLARE return_text VARCHAR(10000) DEFAULT NULL;
DECLARE not_found INT DEFAULT 0;
-- Declare cursor before handler
DECLARE x CURSOR FOR SELECT DISTINCT IFNULL(SMR,'-') SMR
FROM MANIFEST_EDI_SMR WHERE BL_NBR = input_val; OPEN x;
-- handler need to be after cursor
DECLARE CONTINUE HANDLER FOR NOT FOUND SET not_found = 1;
FETCH x INTO;
WHILE NOT_FOUND=0
DO
SET return_text = concat(ifnull(return_text, '') , ' ' , IFNULL(x.SMR, '')) ;
FETCH INTO;
END WHILE;
CLOSE ;
IF char_length(return_text) > 85 THEN
SET return_text = concat(ifnull(substr(return_text,1,85), '') , ' detail asp BL');
END IF;
RETURN return_text;
END;
//
DELIMITER ;
More details can be found at:https://dev.mysql.com/doc/refman/8.0/en/cursors.html
Related
I am trying to convert a MSSQL function into MySQL. Here is what I've done so far. Can someone please take a look at it ?
ALTER FUNCTION [dbo].[GetCommaDelimitedCategoryIDs]
(
#datafeedcategoryinfoid int
)
RETURNS varchar(2000)
AS
BEGIN
DECLARE #category_list varchar(4500), #categoryid varchar(20)
SET #category_list = ''
DECLARE category_cursor CURSOR
LOCAL FAST_FORWARD FOR
SELECT DISTINCT categoryid
FROM category_mapping
WHERE datafeedcategoryinfoid = #datafeedcategoryinfoid
OPEN category_cursor;
FETCH NEXT FROM category_cursor
INTO #categoryid;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #category_list = #category_list + #categoryid + ','
FETCH NEXT FROM category_cursor
INTO #categoryid;
END
CLOSE category_cursor;
DEALLOCATE category_cursor;
IF (LEN(#category_list) > 0)
SET #category_list = SUBSTRING(#category_list, 1, LEN(#category_list) - 1)
RETURN #category_list
END
And here is the MySQL function
DELIMITER $$
CREATE DEFINER=``#`` FUNCTION `GetCommaDelimitedCategoryIDs`(
p_datafeedcategoryinfoid int
) RETURNS varchar(2000) CHARSET latin1
BEGIN
DECLARE v_category_list varchar(4500);
DECLARE v_categoryid varchar(20);
DECLARE category_cursor CURSOR FOR
SELECT DISTINCT categoryid
FROM category_mapping
WHERE datafeedcategoryinfoid = p_datafeedcategoryinfoid;
SET v_category_list = '';
OPEN category_cursor;
myloop: LOOP
FETCH category_cursor INTO v_categoryid;
IF done THEN
LEAVE myloop;
END IF;
SET v_category_list = Concat(v_category_list , v_categoryid , ',');
FETCH category_cursor INTO v_categoryid;
END LOOP;
CLOSE category_cursor;
IF (CHAR_LENGTH(RTRIM(v_category_list)) > 0) THEN
SET v_category_list = SUBSTRING(v_category_list, 1, CHAR_LENGTH(RTRIM(v_category_list)) - 1);
END IF;
RETURN v_category_list;
END
But the above function doesn't return the value. Mysql Workbench doesn't return any error, how do i debug ?
Isn't this a job for group_concat()? Something like:
select group_concat(distinct categoryid order by categoryid SEPARATOR ',')
from category_mapping
where datafeedcategoryinfoid = p_datafeedcategoryinfoid;
Here is a demo of group_concat().
delimiter %%
create procedure getFileID(in fname varchar(100), out fId int)
begin
select ID from File
where Name = fname
into fId;
end %%
delimiter ;
delimiter $$
create procedure FileINFO(in fname varchar(100))
begin
declare SMS_done, Par_don boolean default false;
declare SMSID int;
declare SMSName varchar(100) default "";
declare SMSCode varchar(100) default "";
declare ParamName varchar(100) default "";
declare fId int default 0;
call getFileID(fname, fId);
declare c1 cursor for select ID, Code, Name from SMSTemplate where F_ID = fId;
declare continue handler for not found set SMS_done = true;
open c1;
SMS_loop : loop
fetch from c1 into SMSID, SMSCode, SMSName;
if SMS_done then
close c1;
leave SMS_loop;
end if;
block2 : begin
declare c2 cursor for
select Name from ParameterType where ST_ID = SMSID;
declare continue handler for not found set Par_done = true;
open c2;
Par_loop : loop
fetch from c2 into ParamName;
if SMS_done then
set SMS_done = false;
close c2;
leave Par_loop;
end if;
insert into FileDetails
(FileName, SMSName, SMSCode, ParamName)
values
(fname, SMSName, SMSCode, ParamName);
end loop Par_loop;
end block2;
end loop SMS_loop;
select * from FileDetails;
end $$
delimiter ;
and i get that error
ERROR 1064 (42000): 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 'declare c1 cursor for select ID, Code, Name from SMSTemplate where F_ID = fId;' at line 10
for starters get the declares all grouped together at the top.
Also there is no such thing as fetch into so those two things were fixed.
Par_don / Par_done had a typo in the declare.
Also, for sanity, have a drop if exist for the stored proc right above each one, so it is easily scripted and maintained.
drop procedure if exists FileINFO;
delimiter $$
create procedure FileINFO(in fname varchar(100))
begin
declare SMS_done, Par_done boolean default false;
declare SMSID int;
declare SMSName varchar(100) default "";
declare SMSCode varchar(100) default "";
declare ParamName varchar(100) default "";
declare fId int;
declare c1 cursor for select ID, Code, Name from SMSTemplate where F_ID = fId;
declare continue handler for not found set SMS_done = true;
call getFileID(fname, fId );
open c1;
SMS_loop : loop
fetch c1 into SMSID, SMSCode, SMSName;
if SMS_done then
close c1;
leave SMS_loop;
end if;
block2 : begin
declare c2 cursor for
select Name from ParameterType where ST_ID = SMSID;
declare continue handler for not found set Par_done = true;
open c2;
Par_loop : loop
fetch from c2 into ParamName;
if SMS_done then
set SMS_done = false;
close c2;
leave Par_loop;
end if;
insert into FileDetails
(FileName, SMSName, SMSCode, ParamName)
values
(fname, SMSName, SMSCode, ParamName);
end loop Par_loop;
end block2;
end loop SMS_loop;
select * from FileDetails;
end $$
delimiter ;
Does the table SMSTemplate have a field F_ID??
If not, that could be why you're getting this error.
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 ;
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 ;
I get a error on line 12 (at the endif statement).
I belief I´m doing something wrong within the IF or ELSE, can anyone help me?
DELIMITER $$
CREATE FUNCTION TEST (`param` INT)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE `var` INT;
SET `var` = 1;
IF `param` > 0 THEN
SET `var` = `var` + `param`;
END IF;
RETURN `var`;
END$$
EDIT: (same function with case instead of if, same problem)
DELIMITER $$
CREATE FUNCTION TEST (`param` INT)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE `var` INT;
SET `var` = 1;
SET `var` =
CASE
WHEN `param` > 0 THEN `var` + `param` ELSE `var`
END ;
RETURN `var`;
END$$
Try this instead:
BEGIN
DECLARE `var` INT;
SET var =
CASE
WHEN param > 0 THEN var + 1 ELSE var
END ;
RETURN var;
END$$
Found out it was a bug in PHPMyAdmin, if I added the function with 'add routine' it worked!