Create and call MYSQL Function to find Fibonacci numbers till n numbers - mysql

My approach
DELIMITER $$
CREATE FUNCTION fibonacci(num INT)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE fib1 INT DEFAULT 0;
DECLARE fib2 INT DEFAULT 1;
DECLARE fib3 INT DEFAULT 0;
DECLARE str VARCHAR(255) DEFAULT '01';
IF num = 1 THEN
RETURN fib1;
ELSEIF num = 2 THEN
RETURN CONCAT(fib1, fib2);
ELSE
WHILE num > 2 DO
SET fib3 = fib1 + fib2;
SET fib1 = fib2;
SET fib2 = fib3;
SET num = num - 1;
SET str = CONCAT(str, fib3);
END WHILE;
RETURN str;
END IF;
END $$
DELIMITER ;
If I call above function using SELECT fibonacci(6); it returns 11235 without leading zero(0). How I can show leading zero also?

i think it will help you
DELIMITER $$
CREATE FUNCTION fibonacci_number(n INT) RETURNS INT
DETERMINISTIC
BEGIN
DECLARE f_0 INT default 0;
DECLARE f_1 INT DEFAULT 1;
DECLARE out_fib INT;
DECLARE i INT;
DECLARE f_2 INT;
SET f_0 = 0;
SET f_1 = 1;
SET i = 1;
WHILE (i<=n) DO
SET f_2 = f_0 + f_1;
SET f_0 = f_1;
SET f_1 = f_2;
SET i = i + 1;
END WHILE;
SET out_fib = f_0;
RETURN out_fib;
END $$

Related

mySQL procedure does not commit on commit statement

This is my code:
BEGIN
DECLARE _cnt INT;
DECLARE i INT DEFAULT 0 ;
DECLARE j INT DEFAULT 0 ;
DECLARE _FIPSAPNCombo VARCHAR(30) DEFAULT '00000';
DECLARE _prv_FIPSAPNCombo VARCHAR(30) DEFAULT '00000';
DECLARE _Rollyear INT DEFAULT 2000;
DECLARE _first_Rollyear INT DEFAULT 2000;
DECLARE eof boolean default FALSE;
DECLARE _AvTotal INT;
DECLARE _prv_AvTotal INT default 0;
DECLARE _YOY_PCT INT;
DECLARE _YOY_USD INT;
DECLARE _in_pct INT;
DECLARE _in_usd INT;
DECLARE _last INT;
DECLARE _id INT;
DECLARE _idx INT;
DECLARE _prv_id INT;
DECLARE get_FIPSAPNCombo CURSOR
FOR
SELECT 0, '0', 2000, 1
UNION
SELECT id, FIPSAPNCombo, rollyear, AvTotal
FROM AvHistory_06037 AS h
WHERE substr(h.FIPSAPNCombo,1,8) = _in_FIPSAPNCombo_8
AND h.AvTotal > 0
ORDER BY 2, 3
;
DECLARE CONTINUE HANDLER
FOR NOT FOUND
SET eof = TRUE;
SELECT YOY_PCT, YOY_USD INTO _in_pct, _in_usd FROM AlertSearches WHERE id = _in_AlertSearchesID;
START TRANSACTION;
OPEN get_FIPSAPNCombo;
doit: LOOP
fetch get_FIPSAPNCombo INTO _id, _FIPSAPNCombo, _Rollyear, _AvTotal;
SET _YOY_USD = _AvTotal - _prv_AvTotal;
SET _YOY_PCT = ROUND((((_AvTotal - _prv_AvTotal) / _prv_AvTotal) * 100),0);
IF eof = TRUE THEN
LEAVE doit;
END IF;
IF _FIPSAPNCombo != _prv_FIPSAPNCombo THEN SET _first_Rollyear = _Rollyear; ELSE SET _first_Rollyear = '2000'; END IF;
IF _YOY_PCT >= _in_pct AND _YOY_USD >= _in_usd and _Rollyear != _first_Rollyear THEN
BEGIN
DELETE FROM AvHistoryAlerts WHERE FIPSAPNCombo = _FIPSAPNCombo AND AlertSearchesID = _in_AlertSearchesID;
INSERT INTO AvHistoryAlerts VALUES (_id, _FIPSAPNCombo, '06037', _Rollyear, _AvTotal, _YOY_PCT, _YOY_USD, _prv_id, _prv_AvTotal, _in_AlertSearchesID);
UPDATE AvHistory SET CausalTransfer = NULL WHERE FIPSAPNCombo = _FIPSAPNCombo;
UPDATE AvHistory SET CausalTransfer = 'Green' WHERE id = _id;
SET i = i + 1;
IF mod(i,1000) = 0 THEN insert into error_log VALUES (concat(_in_FIPSAPNCombo_8, ' > calc_YOY_increase i = ', i, ' ',now())); COMMIT; START TRANSACTION; END IF;
END;
END IF;
SET _prv_FIPSAPNCombo = _FIPSAPNCombo;
SET _prv_AvTotal = _AvTotal;
SET _prv_id = _id;
SET eof = FALSE;
END LOOP;
COMMIT;
CLOSE get_FIPSAPNCombo;
END
I thought that the procedure would commit every 1000 records processed and that this would be reflected in the error_log table in real time.
But, the data is only available after the procedure finishes completely and then all the records show up all at once in the error_log table.
That, by itself, is not the issue: what I am concerned about is the the procedure seems to dwell on "waiting for handler commit" for a long time at the end of the procedure.
So, I'm not sure what's going on: is it storing everything in memory or in a temp table or file and then needs a lot if time for cleanup?
I thought that a commit would clear all that... but it does not seem to commit until the end of the whole procedure
Any ideas?

MySQL 5.7 - ASCII Each Character in a String

I'm looking to do some validation of data replication between some different database systems, with different character sets (potentially) and a third party software that migrates the data. To help test an aspect of this, I'm looking to do something like the following.
ASCII(foo) returns the value for the first character in the string. Is there a way to get the ascii values for all characters in a string in one go, in one select statement? Something like concating the values together, separated by a space. E.g. If the string was hello then the output would be 104 101 108 108 111
Reference:
select ascii('h'); -- 104
select ascii('e'); -- 101
select ascii('l'); -- 108
select ascii('o'); -- 111
Just had the same problem, so here is a procedure that does the work:
DELIMITER $$
CREATE PROCEDURE string_to_ascii(IN inputStr VARCHAR(255))
BEGIN
DECLARE strLen INT DEFAULT 0;
DECLARE idx INT DEFAULT 0;
DECLARE current_char VARCHAR(1);
DECLARE current_char_ascii VARCHAR(10);
DECLARE outputStr TEXT;
IF inputStr IS NULL THEN
SET inputStr = '';
END IF;
SET strLen = CHAR_LENGTH(inputStr);
SET idx = 1;
WHILE idx <= strLen DO
SET current_char = SUBSTR(inputStr, idx, 1);
SET current_char_ascii = ASCII(current_char);
IF idx = 1 THEN
SET outputStr = current_char_ascii;
ELSE
SET outputStr = CONCAT(outputStr, ",", current_char_ascii);
END IF;
SET idx = idx+1;
END WHILE;
SELECT outputStr;
END
$$
DELIMITER ;
Usage:
> CALL string_to_ascii('hello');
+---------------------+
| outputStr |
+---------------------+
| 104,101,108,108,111 |
+---------------------+
If you prefer to use it as a function:
DELIMITER //
CREATE FUNCTION string_to_ascii ( inputStr TEXT )
RETURNS TEXT
DETERMINISTIC
BEGIN
DECLARE strLen INT DEFAULT 0;
DECLARE idx INT DEFAULT 0;
DECLARE current_char VARCHAR(1);
DECLARE current_char_ascii VARCHAR(10);
DECLARE outputStr TEXT;
IF inputStr IS NULL THEN
SET inputStr = '';
END IF;
SET strLen = CHAR_LENGTH(inputStr);
SET idx = 1;
WHILE idx <= strLen DO
SET current_char = SUBSTR(inputStr, idx, 1);
SET current_char_ascii = ASCII(current_char);
IF idx = 1 THEN
SET outputStr = current_char_ascii;
ELSE
SET outputStr = CONCAT(outputStr, ",", current_char_ascii);
END IF;
SET idx = idx+1;
END WHILE;
RETURN outputStr;
END; //
DELIMITER ;
And then the usage will be:
> SELECT string_to_ascii('hello');
+--------------------------+
| string_to_ascii('hello') |
+--------------------------+
| 104,101,108,108,111 |
+--------------------------+

MySQL Stored Procedure: Calling a Loop

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);

MYSQL - Capitalize the first letter of the first word in each sentence

I have a column in a mysql table that users have added data. Some users like to use proper capitalization, some like uppercase words, some all lower case.
What I want to do is change:
CHECK BUILDING.
To:
Check building.
And:
DELIVER PAPERS. UNLOCK DOORS.
To:
Deliver papers. Unlock doors.
I assume a function could do this so I can re-use it.
Any ideas?
I tried this but it does each word not the first word in a sentence.
BEGIN
DECLARE c CHAR(1);
DECLARE s VARCHAR(128);
DECLARE i INT DEFAULT 1;
DECLARE bool INT DEFAULT 1;
DECLARE punct CHAR(17) DEFAULT '?.!-';
SET s = LCASE( str );
WHILE i < LENGTH( str ) DO
BEGIN
SET c = SUBSTRING( s, i, 1 );
IF LOCATE( c, punct ) > 0 THEN
SET bool = 1;
ELSEIF bool=1 THEN
BEGIN
IF c >= 'a' AND c <= 'z' THEN
BEGIN
SET s = CONCAT(LEFT(s,i-1),UCASE(c),SUBSTRING(s,i+1));
SET bool = 0;
END;
ELSEIF c >= '0' AND c <= '9' THEN
SET bool = 0;
END IF;
END;
END IF;
SET i = i+1;
END;
END WHILE;
RETURN s;
END
There's no MySQL function to do that. This function capitalize the first letter of every word in a string.
CREATE FUNCTION CAP_FIRST (input VARCHAR(255))
RETURNS VARCHAR(255)
DETERMINISTIC
BEGIN
DECLARE len INT;
DECLARE i INT;
SET len = CHAR_LENGTH(input);
SET input = LOWER(input);
SET i = 0;
WHILE (i < len) DO
IF (MID(input,i,1) = ' ' OR i = 0) THEN
IF (i < len) THEN
SET input = CONCAT(
LEFT(input,i),
UPPER(MID(input,i + 1,1)),
RIGHT(input,len - i - 1)
);
END IF;
END IF;
SET i = i + 1;
END WHILE;
RETURN input;
END;
References link.

MySQL Proc Call - Set Strange Behaviour

I Have a table somewhat like this:
rnumber
number = int, cod = int
SELECT * FROM number WHERE number = 21377 and cod = 55;
returns the correct value;
So i have a proc call to insert:
CREATE DEFINER=`root`#`%` PROCEDURE `create`(IN Numb INT, IN Cod INT, IN qt INT)
BEGIN
SET #Cont = 0;
SET #Init = Numb;
WHILE #Cont < qt DO
SET #Exist = (SELECT count(number) FROM rnumber WHERE number = #Init AND cod = Cod LIMIT 1);
IF #Exist = 0 THEN
INSERT INTO (...)
END IF;
SET #Cont = #Cont + 1;
SET #IniT = #Init + 1;
END WHILE;
END$$
CALL create (21377, 54, 1);
Always give me variable #Exist as 1, so no go on the if, even tho the combination of number and cod does not exists.
Can anyone point me what am i doing wrong?
Thank you.
Try using select into instead of set xx = (select...).
Also having cod = Cod will always return true...
You also need to declare your variables...
Try this one:
CREATE DEFINER=`root`#`%` PROCEDURE `create`(IN p_Numb INT, IN p_Cod INT, IN p_qt INT)
BEGIN
declare v_Exist integer;
declare v_Init integer;
declare v_Exist integer;
SET v_Cont = 0;
SET v_Exist = 0;
SET v_Init = p_Numb;
WHILE v_Cont < p_qt DO
SELECT count(number) into v_Exist FROM rnumber WHERE number = v_Init AND cod = p_Cod LIMIT 1;
IF v_Exist = 0 THEN
INSERT INTO (...)
END IF;
SET v_Cont = v_Cont +1;
SET v_IniT = v_Init + 1;
END WHILE;
END$$