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().
Related
I am trying to create a repetition in 'cursor' that uses 'join', but it doesn't work.
Already tested without 'join' and works normally.
My code:
DECLARE hvDataAtual DATE;
DECLARE manDataAtual DATETIME;
DECLARE motCodAtual INT;
DECLARE done INT DEFAULT FALSE;
DECLARE Crs_vei_man
CURSOR FOR (
SELECT hvedatageracao, hvedatageracao, hvemotorista
FROM tableone INNER JOIN tabletwo ON hveveiculo = manveiculo
WHERE SUBSTRING(mandata, 1, 10) = SUBSTRING(hvedatageracao, 1, 10) LIMIT 10);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN Crs_vei_man;
myloop: LOOP
FETCH Crs_vei_man
INTO hvDataAtual,
manDataAtual,
motCodAtual;
-- Insert 1 row (null, null, null) ?
INSERT INTO testes VALUES(hvDataAtual, manDataAtual, motCodAtual);
IF done THEN
LEAVE myloop;
END IF;
IF motCodAtual > 0 THEN
INSERT INTO testes VALUES('hvDataAtual', 'manDataAtual', 'motCodAtual');
END IF;
END LOOP;
CLOSE Crs_vei_man;
This code is in a stored procedure.
What is happening?
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
I am new to MySQL Stored Procedure. I am writing a code that has a combination or cursors and CASEs.
I have a labeled loop in the cursor. Is it possible to call that labeled loop inside conditions of my CASEs
EDIT:
DROP PROCEDURE IF EXISTS ETOOLS_LATEST.SP_QueryTermsAndConditions;
COMMIT;
DELIMITER $$
CREATE PROCEDURE ETOOLS_LATEST.SP_QueryTermsAndConditions (
IN P_IN_ACCEPTED_BY VARCHAR(32),
OUT P_OUT_ACCEPTED_VERSION VARCHAR(10),
OUT P_OUT_CATEGORY VARCHAR(20),
OUT P_OUT_CURRENT_VERSION VARCHAR(10),
OUT P_OUT_FORCE_ACCEPT BOOLEAN
)
BEGIN
DECLARE noMoreRows BOOLEAN;
DECLARE loopCounter INT DEFAULT 0;
DECLARE rowCount INT DEFAULT 0;
DECLARE acceptedVersion INT(10);
DECLARE currentVersion INT(10);
DECLARE latestGeneral VARCHAR(10);
DECLARE latestBooking VARCHAR(10);
DECLARE curTnc CURSOR
FOR
SELECT a.version AS accepted_version,
a.category,
(
SELECT version
FROM apptermsandconditions c
WHERE is_latest IS True
AND c.category = a.category
) AS current_version
FROM ETOOLS_LATEST.apptermsandconditions a,
ETOOLS_LATEST.usertermsandconditions b
WHERE b.accepted_version = a.id
AND b.accepted_by = P_IN_ACCEPTED_BY;
DECLARE
CONTINUE HANDLER
FOR NOT FOUND
SET noMoreRows = TRUE;
SELECT VERSION
INTO latestGeneral
FROM ETOOLS_LATEST.AppTermsAndConditions
WHERE is_latest IS TRUE
AND CATEGORY = 'General';
SELECT VERSION
INTO latestBooking
FROM ETOOLS_LATEST.AppTermsAndConditions
WHERE is_latest IS TRUE
AND CATEGORY = 'Booking';
OPEN curTnc;
SELECT FOUND_ROWS()
INTO rowCount;
cursorLoop: LOOP
FETCH curTnc
INTO P_OUT_ACCEPTED_VERSION,
P_OUT_CATEGORY,
P_OUT_CURRENT_VERSION;
IF noMoreRows THEN
CLOSE curTnc;
LEAVE cursorLoop;
END IF;
IF P_OUT_ACCEPTED_VERSION <> P_OUT_CURRENT_VERSION THEN
SET P_OUT_FORCE_ACCEPT = 1;
ELSE
SET P_OUT_FORCE_ACCEPT = 0;
END IF;
SELECT P_OUT_ACCEPTED_VERSION,
P_OUT_CATEGORY,
P_OUT_CURRENT_VERSION,
P_OUT_FORCE_ACCEPT;
SET loopCounter = loopCounter + 1;
END LOOP cursorLoop;
CASE rowCount
WHEN 0
THEN
SELECT null, 'General', latestGeneral, 1;
SELECT null, 'Booking', latestBooking, 1;
WHEN 1
THEN
CASE P_OUT_CATEGORY
WHEN 'General'
THEN
SELECT null, 'Booking', latestBooking, 1;
WHEN 'Booking'
THEN
SELECT null, 'General', latestGeneral, 1;
END CASE;
WHEN 2
THEN
SELECT null;
END CASE;
END $$
DELIMITER ;
CALL SP_QueryTermsAndConditions('333333', #P_OUT_ACCEPTED_VERSION, #P_OUT_CATEGORY, #P_OUT_CURRENT_VERSION, #P_OUT_FORCE_ACCEPT);
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 am trying to only execute a block of code if a variable exists. Here is a code snipit. Can you nest Begin...End statements in an IF block?
I've re-designed this several times. Suggestions?
delimiter //
drop trigger if exists example_trigger;//
create trigger example_trigger AFTER UPDATE on some_table for each row
BLOCK1: begin
-- check current status
DECLARE done BOOLEAN DEFAULT FALSE;
-- cap check
if (new.CURRENT_ALLOCATED >= new.TOTAL_ALLOWED_QTY) then
SET done = TRUE;
end if; -- cap check end
-- o
if (done != TRUE and new.O_KEY is not null and new.A_KEY is null) then
OBLOCK: begin
DECLARE done_o BOOLEAN DEFAULT FALSE;
DECLARE pd_nbr INT;
DECLARE no_more_rows BOOLEAN;
DECLARE cur_pd CURSOR FOR
select pd.STATUS_KEY
from PROD_DEL_V pd
join PROD_T p on pd.KEY_NBR = p.KEY_NBR
where pd.STATUS not in ('PU', 'EX')
and p.O_KEY = new.O_KEY;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET done_o = TRUE;
-- run updates
if (done_o != TRUE) then
-- open cursor
OPEN cur_pd;
-- loop start
loop_it: LOOP
FETCH cur_pd INTO pd_nbr;
-- exit loop if..
if no_more_rows = TRUE THEN
CLOSE cur_pd;
LEAVE loop_it;
end if;
INSERT INTO STATUS_TABLE (
STATUS_KEY
, STATUS
, NOTE_TXT
)
(
SELECT
PD.STATUS_KEY
, 'PU' AS STATUS
, concat('example_trigger - MAX has been reached or exceeded [TOTAL_ALLOWED_QTY = ',new.TOTAL_ALLOWED_QTY,' and CURRENT_ALLOCATED = ', new.CURRENT_ALLOCATED, ']') AS NOTE_TXT
FROM PROD_DEL_TABLE PD
WHERE PD.STATUS_KEY = pd_nbr
);
END LOOP loop_it;
end if; -- run updates end
end OBLOCK:; -- end block
end if; -- o
-- a
if (done != TRUE and new.O_KEY is null and new.A_KEY is not null) then
ABLOCK: begin
DECLARE done_a BOOLEAN DEFAULT FALSE;
DECLARE pd_nbr INT;
DECLARE no_more_rows BOOLEAN;
DECLARE cur_pd CURSOR FOR
select pd.STATUS_KEY
from PROD_DEL_V pd
join PROD_T p on pd.KEY_NBR = p.KEY_NBR
join A_O_T a on a.O_KEY = p.O_KEY
where pd.STATUS not in ('PU', 'EX')
and a.A_KEY = new.A_KEY;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET done_a = TRUE;
-- run updates
if (done_a != TRUE) then
-- open cursor
OPEN cur_pd;
-- loop start
loop_it: LOOP
FETCH cur_pd INTO pd_nbr;
-- exit loop if..
if no_more_rows = TRUE THEN
CLOSE cur_pd;
LEAVE loop_it;
end if;
INSERT INTO STATUS_TABLE (
STATUS_KEY
, STATUS
, NOTE_TXT
)
(
SELECT
PD.STATUS_KEY
, 'PU' AS STATUS
, concat('example_trigger - MAX has been reached or exceeded [TOTAL_ALLOWED_QTY = ',new.TOTAL_ALLOWED_QTY,' and CURRENT_ALLOCATED = ', new.CURRENT_ALLOCATED, ']' AS NOTE_TXT
FROM PROD_DEL_TABLE PD
WHERE PD.STATUS_KEY = pd_nbr
);
END LOOP loop_it;
end if; -- run updates end
end ABLOCK; -- end block
end if; -- a
end BLOCK1; -- end large block
//
delimiter ;
What is the problem with IF and BEGIN...END clause? Take a look at this simple example -
CREATE PROCEDURE procedure1(IN Param1 VARCHAR(255))
BEGIN
IF Param1 = 1 THEN
BEGIN
DECLARE i INT;
-- do something
END;
ELSE
BEGIN
DECLARE i INT;
-- do something
END;
END IF;
END