return null value in the JSON_EXTRACT - mysql

MyJsonArray
[{"ID":"D29","PersonID":"23616639"},{"ID":"D30","PersonID":"22629626"}]
and I want from sql Function set this array in to my Table but return null value in the variable and not set record in My database
my function:
DELIMITER $$
CREATE DEFINER=`toshiari`#`localhost` FUNCTION `setTitleRecords`(`Title` VARCHAR(166) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, `List` JSON) RETURNS int(4)
BEGIN
DECLARE Item INT;
DECLARE HolderLENGTH INT;
DECLARE ValidJson INT;
DECLARE ID VARCHAR(166);
DECLARE PersonID VARCHAR(166);
DECLARE S1 VARCHAR(166);
DECLARE S2 VARCHAR(166);
SET ValidJson = (SELECT JSON_VALID(List));
IF ValidJson = 1 THEN
SET HolderLENGTH = (SELECT JSON_LENGTH(List));
SET Item = 0;
WHILE Item < HolderLENGTH DO
SET S1 = CONCAT("'$[",Item, "].ID'");
SET S2 = CONCAT("'$[",Item, "].PersonID'");
SET ID = (SELECT JSON_EXTRACT(List,S1));
SET PersonID = (SELECT JSON_EXTRACT(List,S2));
INSERT INTO `Titles`(`ID`,`PersonID`,`Title`) VALUES (ID, PersonID, Title);
SET Item = Item + 1;
END WHILE;
RETURN 3;
ELSE
RETURN 2;
END IF;
END$$
DELIMITER ;
when I use this command in the Sql commands no problem and return true value
SELECT JSON_EXTRACT('[{"ID":"D29","PersonID":"23616639"},{"ID":"D30","PersonID":"22629626"}]','$[0].ID') return "D29"
return
"D29"
but in when run function from this code
return error and said:
SET #p0='DR'; SET #p1='[{\"ID\":\"D29\",\"PersonID\":\"23616639\"},{\"ID\":\"D30\",\"PersonID\":\"22629626\"}]'; SELECT `setTitleRecords`(#p0, #p1) AS `setTitleRecords`;
#4042 - Syntax error in JSON path in argument 2 to function 'json_extract' at position 1

I created a little test, in order to reproduce your issues. Basically you just need to redeclare S1 and S2, in the following way:
SET S1 = CONCAT('$[',Item,'].ID');
SET S2 = CONCAT('$[',Item,'].PersonID');
And that's it. You can check the test in the following url: https://www.db-fiddle.com/f/2TPgF868snjwcHN3uwoSEA/0

Related

how does mysql user defined function know a selected row was found?

a MYSQL user defined function selects a row from a table. How does the UDF code determine if the selected row was found in the table?
CREATE FUNCTION snippetFolder_folderPath(folder_id int)
RETURNS varchar(512)
BEGIN
declare vFolder_id int;
declare vParent_id int;
declare vPath varchar(512) default '';
declare vFolderName varchar(256) default '';
set vFolder_id = folder_id;
build_path:
while (vFolder_id > 0) do
/* -------- how to know this select statement returns a row?? ---------- */
select a.parent_id, a.folderName
into vParent_id, vFolderName
from SnippetFolder a
where a.folder_id = vFolder_id;
if vPath = ' ' then
set vPath = vFolderName;
else
set vPath = concat_ws( '/', vFolderName, vPath );
end if ;
set vFolder_id = vParent_id;
end while ;
return vPath;
END
https://dev.mysql.com/doc/refman/8.0/en/select-into.html says:
If the query returns no rows, a warning with error code 1329 occurs (No data), and the variable values remain unchanged.
So you could declare a continue handler on warnings, something like the example from the documentation:
BEGIN
DECLARE i INT DEFAULT 3;
DECLARE done INT DEFAULT FALSE;
retry:
REPEAT
BEGIN
DECLARE CONTINUE HANDLER FOR SQLWARNING
BEGIN
SET done = TRUE;
END;
IF done OR i < 0 THEN
LEAVE retry;
END IF;
SET i = i - 1;
END;
UNTIL FALSE END REPEAT;
END
I'll leave it to you to read the documentation and adapt that example to your table and your loop.
Alternatively, if you're using MySQL 8.0 you can use recursive common table expression:
CREATE FUNCTION snippetFolder_folderPath(vFolder_id int)
RETURNS varchar(512)
BEGIN
DECLARE vPath varchar(512) DEFAULT '';
WITH RECURSIVE cte AS (
SELECT folderName, parent_id, 0 AS height
FROM SnippetFolder WHERE folder_id = vFolder_id
UNION
SELECT f.folderName, f.parent_id, cte.height+1
FROM SnippetFolder AS f JOIN cte ON cte.parent_id = f.folder_id
)
SELECT GROUP_CONCAT(folderName ORDER BY height DESC SEPARATOR '/')
INTO vPath
FROM cte;
RETURN vPath;
END
The recursive CTE result is all the ancestors of the row matching vFolder_id, and then one can use GROUP_CONCAT() to concatenate them together as one string.

how to apply while loop for loop query in mysql

CREATE DEFINER=`root`#`localhost` PROCEDURE `test4`()
BEGIN
declare GroupArray text;
DECLARE i INT DEFAULT 0;
DECLARE loopcount INT DEFAULT 0;
declare GroupId varchar (5);
set GroupArray=(select group_concat(distinct groupId) from EventList_View);
SET loopcount = (SELECT LENGTH(GroupArray) -
LENGTH(REPLACE(GroupArray,',', '')));
select loopcount;
WHILE i <= loopcount DO
SET i = i + 1;
SET GroupId = (SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(GroupArray,
',', i),',', -1));
select GroupId;
END WHILE;
END
this is my query i am trying to apply while loop and i want get all groupId but GroupArray [1,2,3]i am getting value but in loop count i am getting 0 can any one please tell me where am doing wrong . why i am unable to get loop count null and why i am not getting value 1,2,3 for group

MySQL script error

I'm new to SQL programming and I decided to make a script. This one might be quite riddled with errors but I'm getting an error that I'm unable to resolve.
DELIMITER $
DROP FUNCTION IF EXISTS crossref$
CREATE FUNCTION crossref()
BEGIN
DECLARE i INT;
DECLARE names VARCHAR(70);
SET i = 1;
myloop: LOOP
SET i=i+1;
IF i = 6 then
LEAVE myloop;
END IF;
SET names = (SELECT NAME FROM cbase_excel_table WHERE ID = i);
INSERT INTO cbase_master(NAME, PERMALINK, HOMEPAGE_URL, CATEGORY_LIST, MARKET, FUNDING, 'STATUS', COUNTRY, REGION, CITY)
SELECT NAME, PERMALINK, HOMEPAGE_URL, CATEGORY_LIST, MARKET, FUNDING, 'STATUS', COUNTRY, REGION, CITY FROM cbase_excel_table WHERE ID = i;
UPDATE cbase_master
SET DESCRIPTION = (SELECT DESCRIPTION FROM cbase_json_table WHERE NAME = names)
SET DOMAIN = (SELECT DOMAIN FROM cbase_json_table WHERE NAME = names)
SET IMAGE_URL = (SELECT IMAGE_URL FROM cbase_json_table WHERE NAME = names)
SET FACEBOOK_URL = (SELECT FACEBOOK_URL FROM cbase_json_table WHERE NAME = names)
SET TWITTER_URL = (SELECT TWITTER_URL FROM cbase_json_table WHERE NAME = names)
SET LINKEDIN_URL = (SELECT LINKEDIN_URL FROM cbase_json_table WHERE NAME = names)
SET CBASE_UUID = (SELECT CBASE_UUID FROM cbase_json_table WHERE NAME = names);
END LOOP myloop;
END$
DELIMITER;
and I'm getting:
#1064 - 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 'BEGIN
DECLARE i INT;
DECLARE names VARCHAR(70);
SET i = 1;
Any help?
An example of a function which shows a major difference to your function:
CREATE FUNCTION `fnFindMaximum`(`a` INT, `b` INT)
/* Before the BEGIN statement there are other things going on - the most important being the return type statement */
RETURNS int(11)
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE returnval INTEGER;
IF a >= b THEN
SET returnval = a;
ELSE
SET returnval = b;
END IF;
RETURN returnval;
END
Your function then goes on to manipulate sql but does not return a value so, as was pointed out by #arkhil, use a StoredProcedure in preference to a function.

Is it possible to create this mysql Function?

I'm a newbie in mysql programming, and i would create a mysql function myFunction with a string parametre; this function query myTable and return a string from the query-result like this example :
myTable
---------------
|id | value |
---------------
| id1 |value1 |
| id2 |value2 |
| id3 |value3 |
| id4 |value4 |
---------------
Calling this function is like this
myFunction('value2#value1#value4')
and must return
'id2#id1#id4'
Thank you very much
This is a demo of how you can do it, of course you can put all together but I find it cleaner to split the functions.
Check the SQL Fiddle
My table
-- the table def
create table myTable (id char(3), value char(6));
insert into myTable values( 'id1', 'value1');
insert into myTable values( 'id2', 'value2');
insert into myTable values( 'id3', 'value3');
insert into myTable values( 'id4', 'value4');
Get a specific id
-- get Id by Value
CREATE function getIdByValue( theValue TEXT )
RETURNS TEXT READS SQL DATA
BEGIN
DECLARE theId TEXT;
DECLARE ok INT DEFAULT FALSE;
DECLARE crs CURSOR FOR
SELECT id FROM myTable where value = theValue;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET ok = TRUE;
SET theId = '';
OPEN crs;
read_loop: LOOP
FETCH crs INTO theId;
IF ok THEN
LEAVE read_loop;
END IF;
END LOOP;
CLOSE crs;
RETURN theId;
END//
MyFunction as you describe
-- the myFunction, usage: myFunction('value2#value1#value4')
CREATE function myFunction( v TEXT )
RETURNS TEXT READS SQL DATA
BEGIN
DECLARE theId TEXT;
DECLARE theIds TEXT;
DECLARE theValue TEXT;
DECLARE vInstr INT;
SET theId = '';
SET theIds = '';
v_loop: LOOP
SET vInstr = INSTR(v,'#');
IF vInstr = 0 THEN
SET theValue = v;
SET theId = getIdByValue(theValue);
ELSE
SET theValue = SUBSTRING(v, 1, vInstr-1);
SET v = SUBSTRING(v, vInstr+1);
SET theId = concat( getIdByValue(theValue), '#');
END IF;
SET theIds = CONCAT(theIds, theId);
IF vInstr = 0 THEN
LEAVE v_loop;
END IF;
END LOOP;
RETURN theIds;
END//
The call
SELECT myFunction( 'value2' );
SELECT myFunction( 'value2#value4' );
SELECT myFunction( 'value2#value4#value1' );
SELECT myFunction( 'value2#value4#value1#value3' );
The results
id2
id2#id4
id2#id4#id1
id2#id4#id1#id3
you can use something like,
CREATE FUNCTION myFunction (param1) RETURNS datatype
[NOT] DETERMINISTIC
statements
check this link for more information
http://www.mysqltutorial.org/mysql-stored-function/
Any reason you couldn't just run this kind of query?
SELECT GROUP_CONCAT(id ORDER BY FIELD(`value`, 'value2', 'value1', 'value4'))
FROM myTable
WHERE `value` IN ('value2','value1','value4')
;
Edited: Added value as first argument to FIELD() function to make it return the ids in the proper order.

Mysql WHERE IN (*)

I have a procedure A which takes an array of strings. By calling another procedure B, i break this array in this format:
'1','2','3','4'
In case there is only one value, it just displays as '1'
I want to return * in case the array passed to the procedure A.
Therefore, my query will be like this: select * from users where userId(*);
What i want is that in case the parameter is null, it should still perform the IN using.
** EDIT **
Nothing much of query
CREATE DEFINER=`root`#`localhost` PROCEDURE `listAll`(IN id varchar(200))
BEGIN
set #t = lib_explode(',',id);
select * from city where ID in(#t);
END
Procedure B
CREATE DEFINER=`root`#`localhost` FUNCTION `lib_explode`(sSepar VARCHAR(255), saVal TEXT) RETURNS varchar(200) CHARSET utf8
body:
BEGIN
IF sSepar IS NULL OR saVal IS NULL THEN LEAVE body; END IF;
SET #saTail = saVal;
SET #iSeparLen = LENGTH( sSepar );
set #mystring = '';
set #current_pos = 1;
create_layers:
WHILE #saTail != '' DO
# Get the next value
SET #sHead = SUBSTRING_INDEX(#saTail, sSepar, 1);
SET #saTail = SUBSTRING( #saTail, LENGTH(#sHead) + 1 + #iSeparLen );
-- INSERT INTO lib_Explode SET val = #sHead;
if(#current_pos > 1) then
set #mystring = concat(#mystring,',',concat("'",#shead,"'"));
else
set #mystring = concat(#mystring,concat("'",#shead,"'"));
end if;
set #current_pos = #current_pos + 1;
END WHILE;
return #mystring;
END