SQL: Using a variable within a text field - mysql

I'm new at this so please bear with me. I've created the following stored procedure.
DELIMITER //
CREATE PROCEDURE REMARK()
BEGIN
#declare variable
DECLARE v_newid, v_oldid VARCHAR(255);
DECLARE done INT DEFAULT FALSE;
#declare cursor
DECLARE cur1 CURSOR FOR
SELECT new, old
FROM mydb.`tbl_id`;
#declare handle
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
#open cursor
OPEN cur1;
#starts the loop
the_loop: LOOP
#get the values of each column into our variables
FETCH cur1 INTO v_newid, v_oldid;
IF done THEN
LEAVE the_loop;
END IF;
#Insert it
INSERT INTO cherrycasino.`tbl_remarks` (player_id, user_tool_id, text)
VALUES (v_newid, '103', 'User Copied from ES id:v_oldid');
END LOOP the_loop;
CLOSE cur1;
END //
DELIMITER ;
It is working as it should except for one thing. I want to insert some text in tbl_remarks using a variable I got from the cursor.
VALUES (v_newid, '103', 'User Copied from ES id:v_oldid');
I cannot transform back the variable v_oldid back. Am I missing some escape sequence here?

Turns out the answer was a simple concat of the string I want to use plus the variable.
VALUES (v_newid, '103', CONCAT('User Copied from ES id:', v_oldid));

Related

Can I access the information of an error in a continue handler?

In a stored procedure, I can have a continue handler that handles errors. Can I somehow access the details of the respective error inside the handler?
Small example:
DROP PROCEDURE IF EXISTS `DO_SOMETHING_WRONG`;
DELIMITER $$
CREATE PROCEDURE `DO_SOMETHING_WRONG`()
BEGIN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Hey, this is an error!';
END $$
DELIMITER ;
(That's obviously the failing part of the example)
DROP PROCEDURE IF EXISTS `CALL_SOMETHING_WRONG`;
DELIMITER $$
CREATE PROCEDURE `CALL_SOMETHING_WRONG`()
BEGIN
DECLARE ERROR_OCCURRED BOOLEAN DEFAULT FALSE;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET ERROR_OCCURRED := TRUE;
CALL DO_SOMETHING_WRONG();
IF ERROR_OCCURRED IS TRUE THEN
SELECT 'An error occurred!' AS Output;
ELSE
SELECT 'No error occurred!' AS Output;
END IF;
END $$
DELIMITER ;
When I call CALL CALL_SOMETHING_WRONG(); it gives me An error occurred! as it should, but can I let it tell me, what error? So, get hold of the 45000 and the Hey, this is an error! in this example?

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.

MySQL Stored Function Syntax Error

I've spent hours and I can't understand why this is highlighted red and I don't know what my error is.
CREATE FUNCTION Student_Section_Count(StudentID INT)
Returns INT
Begin
DECLARE section_Registred INT;
SET section_Registred= (Select COUNT(DISTINCT Section.ID) as 'Students Registration Count'
FROM Section
Inner Join
Registration on registration.StudentID=Section.ID
Where registration.StudentID=StudentID);
Return Section_Registred;
END$$
Delimiter;
It highlights END and Delimiter, as well as INT from Return INT
By default semi-colon ; is the delimiter in mysql. So when using a mysql client, the function definition that is passed to server is only up to the first semi-colon i.e. DECLARE section_Registred INT;. Rest of the definition of function is not passed to server. This produces an error. To incorporate semi-colon in function definition you need to change your delimiter from semi-colon to some thing else. So before defining the function write the below sql to change the delimiter:
DELIMITER $$.
After the above sql write sql for your function. Append the new delimiter $$ to END at the end of definition of your function. Now the whole definition of function is passed to server up to the new delimiter. This will fix your error. Change the delimiter back to default after your function definition ends as below:
DELIMITER ;.
Also remember to choose a delimiter that is not present anywhere inside your function definition.
Well, I guess I figured it out on my own.
DELIMITER $$
CREATE FUNCTION Student_Section_Count(StudentID INT)
Returns INT
Begin
DECLARE section_Registred INT;
SET section_Registred= (Select COUNT(DISTINCT Section.ID) as 'Students Registration Count'
FROM Section
Inner Join
Registration on registration.StudentID=Section.ID
Where registration.StudentID=StudentID);
Return Section_Registred;
END$$

postgres - modifying xml (MySql UpdateXml alternative)

I'm migrating mysql database to postgres and ran into a roadblock regarding some basic xml functionality. In MySql I had stored procedures which would replace nodes inside xml document but cannot find any way to do so in postgres.
Here's my stored proc from mysql:
CREATE DEFINER=`root`#`localhost` PROCEDURE `SP_UpdateExamFilesXmlNode`(examFileId int, xPathExpression varchar(128), xmlNode longtext)
BEGIN
DECLARE xmlData longtext;
DECLARE newXmlData longtext;
DECLARE xmlNodeCount int;
SET xmlData = NULL;
SELECT xml_data INTO xmlData FROM sonixhub.exam_files WHERE id = examFileId;
IF xmlData IS NOT NULL THEN
-- check if the node already exists and if it does then simply update it
SET xmlNodeCount = ExtractValue(xmlData, CONCAT('count(',xPathExpression,')'));
IF xmlNodeCount > 0 THEN
SET newXmlData = UpdateXML(xmlData, xPathExpression, xmlNode);
-- if node doesn't exist then we have to add it manually
ELSE
SET newXmlData = REPLACE(xmlData, '</ImageXmlData>', CONCAT(xmlNode, '</ImageXmlData>'));
END IF;
UPDATE sonixhub.exam_files SET xml_data = newXmlData WHERE id = examFileId;
ELSE
-- there is no xml found so create xml from scratch and insert the node
SET xmlData = CONCAT('<ImageXmlData>',xmlNode,'</ImageXmlData>');
UPDATE sonixhub.exam_files SET xml_data = xmlData WHERE id = examFileId;
END IF;
END
Is there any way to replicate this functionality in postgres function instead of moving the logic into the application itself?
EDIT - FOUND A SOLUTION TO MY PROBLEM
I found a solution using mix of postgres xml and string formatting functions.
examFileId is used to find the row to be updated with the xml, change the code with your table info
is the hardcoded root node in my case, but you can change it to whatever you like.
Here's how you call the function:
-- this adds <DicomTags> node to your xml value in the table, if <DicomTags> already exists then it's replaced by the one passed in
select update_exam_files_xml_node(1, '/ImageXmlData/DicomTags', '<DicomTags><DicomTag>xxx</DicomTag></DicomTags>');
-- this adds <Settings> node to your xml value in the table, if <Settings> already exists then it's replaced by the one passed in
select update_exam_files_xml_node(1, '/ImageXmlData/Settings', '<Settings>asdf</Settings>');
CREATE OR REPLACE FUNCTION update_exam_files_xml_node(examFileId int, xPathExpression text, xmlNode text)
RETURNS void AS
$BODY$
DECLARE xmlData xml;
DECLARE newXmlData xml;
DECLARE xmlNodeCount int;
DECLARE replaceTag text;
BEGIN
SELECT xml_data INTO xmlData FROM exam_files WHERE id = examFileId;
IF xml_is_well_formed(xmlNode) = false THEN
PERFORM add_error_log('update_exam_files_xml_node', 'xmlNode is not well formed xml');
RETURN;
END IF;
IF xmlData IS NOT NULL THEN
-- check if the node already exists and if it does then simply update it
IF xmlexists(xPathExpression PASSING BY REF xml(xmlData)) = true THEN
-- get the node name
replaceTag := regexp_replace(xPathExpression, '/.*/', '');
-- replace the existing node with the newly passed in node
newXmlData := xml(regexp_replace(xmlData::text, '<'||replaceTag||'>.*</'||replaceTag||'>', xmlNode));
-- if node doesn't exist then we have to add it manually
ELSE
newXmlData := xml(REPLACE(xmlData::text, '</ImageXmlData>', xmlNode||'</ImageXmlData>'));
END IF;
UPDATE exam_files SET xml_data = newXmlData WHERE id = examFileId;
ELSE
-- there is no xml found so create xml from scratch and insert the node
xmlData := '<ImageXmlData>'||xmlNode||'</ImageXmlData>';
UPDATE exam_files SET xml_data = xmlData WHERE id = examFileId;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Glad you got a solution. To be honest, string formatting functions tend to be a bit difficult to reliably use inside SGML due to issues relating to hierarchies of languages. I.e. regexps have hard limits as to what they can do.
A better solution is likely to be to go a very different direction and write your functions in PL/PerlU or PL/Python, and use existing XML processing capabilities for those languages. This is likely to give you a better and more robust solution.

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.