Mysql recursive procedure - mysql

I have a table name css_diectory with 3 columns directory_id, directory-name and root_directory. I am storing hierarchical directory structure in this table. I have written a procedure to retrieve all the descendants given the directory_id. But it doesn't work. Can anyone please help me.
Here is the procedure
CREATE PROCEDURE getDescendants
(IN rootId varchar(32), INOUT desecendantsFolderId varchar(3200))
BEGIN
DECLARE endOfRecord INTEGER DEFAULT 0;
DECLARE folderId varchar(32) DEFAULT "";
DECLARE folderName varchar(32) DEFAULT "";
DECLARE folderCursor CURSOR FOR
Select directory_id, directory_name from css_directory where root_directory=rootId;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET endOfRecord = 1;
OPEN folderCursor;
getFolderId: LOOP
FETCH folderCursor INTO folderId, folderName;
IF endOfRecord = 1 THEN
LEAVE getFolderId;
END IF;
Call getDescendants(folderId,desecendantsFolderId);
SET desecendantsFolderId = CONCAT(folderId,",",desecendantsFolderId);
call getDescendants(folderId,desecendantsFolderId);
END LOOP getFolderId;
END
Edit: The output of this procedure is always a null set. It does not produce any error

I'm not 100% sure I follow what you're doing, but it looks like there's a problem here:
SET desecendantsFolderId = CONCAT(folderId,",",desecendantsFolderId);
When any argument to CONCAT() is null, then the return value is null. Presumably descendantsFolderId is initially null, and if so, I don't see where that would change.
There are several ways to remedy this, but here is one of them:
SET desecendantsFolderId = NULLIF(CONCAT_WS(",",folderId,desecendantsFolderId),"");
CONCAT_WS() is like CONCAT(), except the first argument is used as a separator amd null arguments beyond the first one are disregarded, and empty string is returned if all subsequent arguments are null. NULLIF() is probably not technically needed, based on the rest of the code, but will ensure that the final result of CONCAT_WS() will be turned back to null if the input args are indeed all null.

Related

MYSQL Stored Procedure to Iterate Json Array Data

I have a couple of columns that are json arrays that have datetime data like this:
["2017-04-18 11:05:00.000000"]
["2017-04-20 11:05:00.000000"]
["2017-04-22 11:05:00.000000"]
["2017-12-11 22:14:02.000000", "2017-12-11 22:14:08.000000", "2017-12-11 22:19:13.000000", "2017-12-11 22:20:44.000000", "2017-12-11 22:21:54.000000", "2017-12-11 22:23:09.000000"]
["2017-12-13 13:21:04.000000"]
["2017-12-14 13:10:44.000000", "2017-12-14 13:21:51.000000"]
["2017-12-15 13:27:21.000000", "2017-12-15 13:30:21.000000"]
["2017-12-16 15:15:22.000000"]
The goal is to parse out the datetime data and store it into a separate table from which I plan on doing some fun stuff. Currently, it only inserts the first record only, and it inserts it ~180000 times. My current code is:
BEGIN
DECLARE finished INTEGER DEFAULT 0;
DECLARE i INTEGER DEFAULT 0;
DECLARE usages VARCHAR(4000);
-- declare cursor for employee email
DEClARE curUsages
CURSOR FOR
SELECT associated_usages from usagesTbl where associated_usages not like '[]';
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET finished = 1;
OPEN curUsages;
getUsages: LOOP
FETCH curUsages INTO usages;
IF finished = 1 THEN
LEAVE getUsages;
END IF;
WHILE i < JSON_LENGTH(usages) DO
INSERT INTO usagesTbl VALUES (JSON_EXTRACT(usages, CONCAT('$[',i,']')));
SET i = i + 1;
END WHILE;
SET i = 0;
END LOOP getUsages;
CLOSE curUsages;
END;
it seems that the while loop variable "i" is not increasing, and I am getting constantly stuck in the loop. The reason for me thinking this is that I pulled out the JSON_EXTRACT code and wrote this for testing:
set #i = 0;
select JSON_EXTRACT(associated_usages, CONCAT('$[',#i,']')) from usagesTbl where associated_usages not like '[]';
I can change the value of #i to whatever index I want and I get the right data. Im just stuck on why it doesn't work in the while loop during the stored procedure. Any help is greatly appreciated!
not sure if this could be the issue, but I see this:
DEClARE curUsages
Should be this:
DECLARE curUsages
Can it be the simple typo ? (the 1 for the L)
Fixed it! It somehow created an infinite loop that just kept on inserting data even when the stored proc said it was done running. I dropped and recreated the table, and changed the datatype of usages back from VARCHAR to json, and it worked like a charm.

Converting delimited values into a comma separated list

My Webapp (PHP/jQuery/MySQL) has features which enable me to send out nicely formatted html email notifications to my customers based on certain events. The code works nicely and merges data from my Database into form fields although I need to enhance it to be able to provide enriched/localised/reformatted data in some circumstances.
For example:
- Provide date/time values in a user's own timezone
- Provide monetary values formatted to a user's locale
This requires me to do another pass of the email content to detect whether any fields remain unmerged before sending the email off to the user and if so, to format those field values appropriately before sending the email. Therefore what I want to do is extract a list of all delimited fieldnames from a table field value and return that list in comma delimited form.
I can already count how many times a delimeter appears
I can also find the position of the first delimeter
It looks like it would be easy to split the values if I was using the same opening and closing delimeters but because I have many email templates already in use, this isn't currently viable
I don't have any code for this yet. I'm just trying to avoid writing my own MySQL function to do this, by using existing MySQL functions if they are capable of doing this.
I've tried using various combinations of SUBSTRING, SUBSTRING_INDEX, LOCATE.
So what I need to be able to do is something like this:
SELECT msg_id, values_found_between(msg_content,"<",">") AS comma_delimited_list;
So for example, with source data of...
msg_id | msg_content
-------+------------
1 | The quick brown <fox> jumps over the lazy <dog>
2 | The quick brown fox jumps over the lazy dog
I can get a resulting recordset such as this:
msg_id | comma_seperated_list
-------+------------
1 | fox,dog
Alright, I had a crack and this seems to work well:
CREATE FUNCTION db.`FN_find_values_between`(`in_haystack` VARCHAR(10000), `in_opening_delimiter` VARCHAR(1),`in_closing_delimiter` VARCHAR(1)) RETURNS varchar(1000) CHARSET utf8
BEGIN
DECLARE numFoundOpen INT DEFAULT 0;
DECLARE numFoundClose INT DEFAULT 0;
DECLARE numFoundTarget INT DEFAULT 0;
DECLARE numCurrentIndex INT DEFAULT 0;
DECLARE strOutput VARCHAR(1000) DEFAULT "";
DECLARE numSearchFromPos INT DEFAULT 1;
DECLARE numCurrentCharPosStart INT DEFAULT 1;
DECLARE numCurrentCharPosEnd INT DEFAULT 1;
DECLARE strCurrentFieldname VARCHAR(50) DEFAULT "";
DECLARE numLength INT DEFAULT 0;
SET numFoundOpen=
(SELECT
ROUND ((LENGTH(in_haystack)- LENGTH( REPLACE (in_haystack, in_opening_delimiter, ""))) / LENGTH(in_opening_delimiter)));
SET numFoundClose=
(SELECT
ROUND ((LENGTH(in_haystack)- LENGTH( REPLACE (in_haystack, in_closing_delimiter, ""))) / LENGTH(in_closing_delimiter)));
IF (numFoundOpen=numFoundClose) THEN
SET numFoundTarget=numFoundOpen;
END IF;
WHILE numCurrentIndex < numFoundTarget DO
SET numCurrentIndex=numCurrentIndex+1;
SET numCurrentCharPosStart = LOCATE(in_opening_delimiter, in_haystack, numSearchFromPos);
SET numCurrentCharPosEnd = LOCATE(in_closing_delimiter, in_haystack, numSearchFromPos);
SET numLength=1+(numCurrentCharPosEnd-numCurrentCharPosStart);
SET strCurrentFieldname=SUBSTRING(in_haystack,numCurrentCharPosStart,numLength);
SET strOutput=CONCAT(strOutput,strCurrentFieldname,",");
SET strCurrentFieldname="";
SET numSearchFromPos=numCurrentCharPosEnd+1;
END WHILE;
IF (strOutput <> "") THEN
SET strOutput=LEFT(strOutput,LENGTH(strOutput)-1);
END IF;
RETURN strOutput;
END;
As per the code above, I managed to write my own MySQL function to do this.

Calling functions within function in MySQL returns NULL

I don't understand why when I call my SQL Function inside another Function values are lost. Basically I have something like this:
CREATE FUNCTION `myCustomFunctionA`(paramOne INTEGER, paramTwo INTEGER) RETURNS INT(11)
BEGIN
DECLARE outputOne INT(11);
DECLARE outputTwo INT(11);
SET outputOne = myCustomFunctionB(paramOne);
SET outputTwo = myCustomFunctionB(paramTwo);
RETURN myCustomFunctionC(outputOne, outputTwo);
END
Please note that all of these functions return each an integer when called outside myCustomFunctionA. I.E: Running SELECT myCustomFunctionB(paramTwo); actually returns X value and same for paramOne. However when these functions are called inside myCustomFunctionA it's always returning NULL.
So far I tried to return directly paramOne and paramTwo and values are correct. But if I set function to return outputOne or outputTwo after running myCustomFunctionB then they'd also return NULL.
This seems to be something silly I'm missing but I can't see it so any help or tip in the right direction would be really apprecciated. Thanks.

MySQL function doesn't work with unicode strings

I have a MySQL function which does some string replacement in a specified string. I simplyfied this function to return it's argument.
CREATE FUNCTION replace_details(
id INT UNSIGNED,
message VARCHAR(1000))
RETURNS VARCHAR(1000) LANGUAGE SQL
BEGIN
RETURN message;
END;
;;
This function is called from before insert trigger, so the inserted string is modified. Everything works as expected while I'm using english text, but as soon as I'm trying to insert something else (for example russian) it makes my string unreadable. Actually I get only ? sign in a database. If I'm using any other function in trigger it works fine
For example:
SET NEW.message = CONCAT(NEW.message, ' test');
but as soon as I'm using my custom function which actually does nothing, but returns what it got, inserted string becomes unreadable.
I guess I need to somehow specify that my function works with unicode, but how?
MySQL server version: 5.7.1-m11
I found it.
CREATE FUNCTION replace_details(
id INT UNSIGNED,
message VARCHAR(1000) CHARACTER SET UTF8)
RETURNS VARCHAR(1000) CHARACTER SET UTF8 LANGUAGE SQL
BEGIN
RETURN message;
END;
;;
works!

Create a MySQL procedure variable which is initialized when not provided

I need to create a MYSQL procedure where the procedure accepts several parameters and works with them. However, in the case where it is not present, the parameter variables pick some 'default' values and continue. Similar to how the pseudo-function-overload is handled in PHP.
This code is what I could come up with.
CREATE PROCEDURE PROC_INS_CONTENT_TEST(IN DATA_VAL LONGTEXT)
BEGIN
IF (DATA_VAL IS NULL) THEN SET DATA_VAL='DEFAULT'; END IF;
INSERT INTO CONTENT_TEST (DATA) VALUES (DATA_VAL);
END
And this code does not work the way I want it to behave. Is there a way to assign the default value to the variable right when the parameter is declared?
Yes there is.
If you want to set default value on variable on your function/procedure you can do this:
CREATE PROCEDURE PROC_INS_CONTENT_TEST(IN DATA_VAL LONGTEXT)
BEGIN
DECLARE my_data_double DOUBLE DEFAULT 0;
DECLARE my_data_varchar VARCHAR(20) DEFAULT 'default_value';
DECLARE DATA_VAL LONGTEXT DEFAULT 'default_value';
DECLARE my_data_integer INT DEFAULT 0;
END
Or if you want to assign value you can do something like:
SET my_data_value = 12345;
inside your function/procedure.