mysql cursor - select IDs in stament - mysql

It returns IDs as string, it returns only one row which it has first ID. "7,6,5" It returns only 7; How can we correct this problem?
CREATE DEFINER=`root`#`localhost`
PROCEDURE `GET_COMPANION`(IN paramEmployeeId INT)
BEGIN
DECLARE counter INTEGER DEFAULT 0;
DECLARE v_finished INTEGER DEFAULT 0;
DECLARE v_companion varchar(100) DEFAULT "";
DECLARE v_companion_list varchar(100) DEFAULT "";
-- declare cursor for companion_id
DEClARE companion_cursor CURSOR FOR
SELECT companion_id FROM employee_has_companion ehc
WHERE ehc.employee_id = paramEmployeeId;
-- declare NOT FOUND handler
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1;
OPEN companion_cursor;
get_companion: LOOP
FETCH companion_cursor INTO v_companion;
IF v_finished = 1 THEN
LEAVE get_companion;
END IF;
-- build companion list
SET v_companion_list = CONCAT(v_companion,",",v_companion_list);
END LOOP get_companion;
CLOSE companion_cursor;
SELECT * FROM companion co
LEFT JOIN citizenship ci
ON co.citizenship_id = ci.citizenship_id
WHERE co.companion_id IN( SUBSTRING(v_companion_list,
1,LENGTH(v_companion_list)-1));
END

You can use FIND_IN_SET(str,strlist) to check existence of a string in a list of comma separated values.
Change:
SELECT * FROM companion co
LEFT JOIN citizenship ci
ON co.citizenship_id = ci.citizenship_id
WHERE co.companion_id IN( SUBSTRING(v_companion_list,
1,LENGTH(v_companion_list)-1));
To:
SELECT * FROM companion co
LEFT JOIN citizenship ci
ON co.citizenship_id = ci.citizenship_id
WHERE FIND_IN_SET( co.companion_id, v_companion_list ) > 0;

Related

Why my Procedure with CONCAT show me a NULL value?

I'm trying to run this code on MySQL WorkBench:
DELIMITER $$
CREATE PROCEDURE lavoratore_superficie(IN _superficie CHAR(5),
OUT codiciFiscali VARCHAR(255))
BEGIN
DECLARE finito INTEGER DEFAULT 0;
DECLARE codiceFiscale VARCHAR(255) DEFAULT '';
DECLARE cursoreCodici CURSOR FOR
SELECT distinct(TL.Capocantiere)
FROM superficie SU INNER JOIN lottomateriale LM on SU.Codice = LM.Superficie INNER JOIN lavoro LA ON LM.Lavoro = LA.Codice INNER JOIN divisionelavoro DT ON DT.Lavoro = LA.Codice
INNER JOIN turno TU ON TU.Codice = DT.Turno INNER JOIN turnolavoro TL ON TL.Turno = DT.Turno
WHERE SU.Codice = _superficie;
DECLARE CONTINUE HANDLER
FOR NOT FOUND SET finito = 1;
OPEN cursoreCodici;
preleva: LOOP
FETCH cursoreCodici INTO codiceFiscale;
IF finito = 1 THEN
LEAVE preleva;
END IF;
SET codiciFiscali = CONCAT(codiceFiscale, ';', codiciFiscali);
END LOOP preleva;
CLOSE cursoreCodici;
END $$
DELIMITER ;
Then I try to visualize the result set of my query into a local variable with the CONCAT function:
SET #codiciFiscali = '';
CALL lavoratore_superficie('SU001', #codiciFiscali);
SELECT #codiciFiscali;
But after the CALL if I select #codiciFiscali the result set is NULL.
Since codiciFiscali is declared as an OUT parameter, the initial value of #codiciFiscali is not being passed to the procedure. So the variable defaults to NULL.
Either add
SET codiciFiscali = '';
before the loop, or change the parameter to INOUT so it will concatenate to the caller's value.

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.

Get statistics from MySQL json rows [duplicate]

I have a json object which has list of products under a bill. I want to write a mysql function for it which reads the data from the json and iterates over it one by one and inserts the same data to product and bill tables.
Here is my json object
{"billNo":16,"date":"2017-13-11 09:05:01","customerName":"Vikas","total":350.0,"fixedCharges":100,"taxAmount":25.78,"status":paid,"product":[{"productId":"MRR11","categoryId":72,"categoryName":"Parker Pen","cost":200,"quantity":2,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}},{"productId":"MRR12","categoryId":56,"categoryName":"Drawing Books","cost":150,"quantity":3,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}}]}
Here I have a mysql function which reads the data from the JSON
CREATE DEFINER=`mydb`#`%` FUNCTION `raiseOrder`(dataObject Json)
RETURNS bigint(11)
BEGIN
DECLARE billNo BIGINT(11) DEFAULT NULL;
DECLARE customerName VARCHAR(64);
DECLARE date datetime DEFAULT NOW();
DECLARE total Float(12,2);
DECLARE taxamt Float(12,2);
DECLARE fixedCharges Float(12,2);
DECLARE products json;
DECLARE productId bigint(15) DEFAULT NULL;
DECLARE categoryId bigint(11);
DECLARE cost float;
DECLARE categoryName varchar(64);
DECLARE quantity int default 0;
DECLARE supplierId bigint(11);
DECLARE supplierName varchar(128);
SET billNo = (SELECT JSON_EXTRACT(dataObject, "$.billNo"));
SET customerName = (SELECT JSON_EXTRACT(dataObject, "$.customerName"));
SET products = (SELECT JSON_EXTRACT(dataObject, "$.products"));
SET productId = (SELECT JSON_EXTRACT(products, "$[0].productId"));
RETURN 1;
END
Now with these lines
SET products = (SELECT JSON_EXTRACT(dataObject, "$.products"));
SET productId = (SELECT JSON_EXTRACT(products, "$[0].productId"));
I get the inner products json and the id of the 0th product. But I want a way to iterate over the array of the products.
You can use a WHILE loop in conjunction with JSON_LENGTH to achieve this:
DECLARE json, products, product VARCHAR(4000);
DECLARE i INT DEFAULT 0;
SELECT '{"billNo":16,"date":"2017-13-11 09:05:01","customerName":"Vikas","total":350.0,"fixedCharges":100,"taxAmount":25.78,"status":"paid","product":[{"productId":"MRR11","categoryId":72,"categoryName":"Parker Pen","cost":200,"quantity":2,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}},{"productId":"MRR12","categoryId":56,"categoryName":"Drawing Books","cost":150,"quantity":3,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}}]}
' INTO json;
SELECT json->"$.product" INTO products;
WHILE i < JSON_LENGTH(products) DO
SELECT JSON_EXTRACT(products,CONCAT('$[',i,']')) INTO product;
SELECT product;
SELECT i + 1 INTO i;
END WHILE;
You'll probably need to do more than simply 'SELECT product' though ;-)
NOTE: MySQL JSON functions were added in 5.7.8 so you'll need to check your MySQL version first.
Extension to this answer, and if you want to loop through the keys of json object, you can do this via this way
declare _keys int default 0;
declare i int default 0;
declare _current_key varchar(50) default '';
select JSON_KEYS(product) into _keys;
while i < JSON_LENGTH(_keys) do
select json_extract(json_unquote(_keys), concat('$[', i, ']')) into _current_key;
set i = i + 1;
end while;

MySQL trigger on insert of text going into infinite loop

There are three tables: users, ap_name_bank_m and ap_name_bank_h. users table has three columns 'name_eng' (name of user in english), 'name_gdn_eng'(name of user's guardian in english) and 'category'.
ap_name_bank_m and ap_name_bank_h are corpus of names for each category of name: 'm' or 'h'.
When a row is updated I want to check if each word of both names in present in either of two tables ap_name_bank_m and ap_name_bank_h.
Whichever count is higher that category will be assigned. The below code which I have written is going into infnite loop and I am getting "MySQL server has gone away error". Can someone tell me where I am wrong?
Assume name_eng and name_gdn_eng will only contain words with spaces and nothing else.
DELIMITER $$
create trigger set_cat before update on users_table for each row
BEGIN
declare words text;
declare word varchar(50);
declare num_m int default 0;
declare num_h int default 0;
declare len int default 0;
set words = concat(new.name_eng,' ',new.name_gdn_eng);
iterator:
LOOP
set word = substring_index(words,' ',1);
set num_m = EXISTS(select 1 from ap_name_bank_m where name=word) + num_m;
set num_h = EXISTS(select 1 from ap_name_bank_h where name=word) + num_h;
set words = trim(replace(words,word,''));
END LOOP iterator;
if (num_m > num_h) then set new.category='M'; end if;
if (num_h > num_m) then set new.category='H'; end if;
END $$
DELIMITER ;
I found a better way to do this. No need for loop.
BEGIN
declare words text;
declare word varchar(50);
declare num_m int default 0;
declare num_h int default 0;
set words = concat(new.name_eng,' ',new.name_gdn_eng);
set num_h = (select count(*) from ap_name_bank_h where match(name) against (words in natural language mode));
set num_m = (select count(*) from ap_name_bank_m where match(name) against(words in natural language mode));
/*
iterator:
LOOP
set word = substring_index(words,' ',1);
set num_m = EXISTS(select 1 from ap_name_bank_m where name=word) + num_m;
set num_h = EXISTS(select 1 from ap_name_bank_h where name=word) + num_h;
set words = trim(replace(words,word,''));
END LOOP iterator;*/
if (num_m > num_h) then set new.category='M'; end if;
if (num_h > num_m) then set new.category='H'; end if;
END

Loop through JSON object in mysql function

I have a json object which has list of products under a bill. I want to write a mysql function for it which reads the data from the json and iterates over it one by one and inserts the same data to product and bill tables.
Here is my json object
{"billNo":16,"date":"2017-13-11 09:05:01","customerName":"Vikas","total":350.0,"fixedCharges":100,"taxAmount":25.78,"status":paid,"product":[{"productId":"MRR11","categoryId":72,"categoryName":"Parker Pen","cost":200,"quantity":2,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}},{"productId":"MRR12","categoryId":56,"categoryName":"Drawing Books","cost":150,"quantity":3,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}}]}
Here I have a mysql function which reads the data from the JSON
CREATE DEFINER=`mydb`#`%` FUNCTION `raiseOrder`(dataObject Json)
RETURNS bigint(11)
BEGIN
DECLARE billNo BIGINT(11) DEFAULT NULL;
DECLARE customerName VARCHAR(64);
DECLARE date datetime DEFAULT NOW();
DECLARE total Float(12,2);
DECLARE taxamt Float(12,2);
DECLARE fixedCharges Float(12,2);
DECLARE products json;
DECLARE productId bigint(15) DEFAULT NULL;
DECLARE categoryId bigint(11);
DECLARE cost float;
DECLARE categoryName varchar(64);
DECLARE quantity int default 0;
DECLARE supplierId bigint(11);
DECLARE supplierName varchar(128);
SET billNo = (SELECT JSON_EXTRACT(dataObject, "$.billNo"));
SET customerName = (SELECT JSON_EXTRACT(dataObject, "$.customerName"));
SET products = (SELECT JSON_EXTRACT(dataObject, "$.products"));
SET productId = (SELECT JSON_EXTRACT(products, "$[0].productId"));
RETURN 1;
END
Now with these lines
SET products = (SELECT JSON_EXTRACT(dataObject, "$.products"));
SET productId = (SELECT JSON_EXTRACT(products, "$[0].productId"));
I get the inner products json and the id of the 0th product. But I want a way to iterate over the array of the products.
You can use a WHILE loop in conjunction with JSON_LENGTH to achieve this:
DECLARE json, products, product VARCHAR(4000);
DECLARE i INT DEFAULT 0;
SELECT '{"billNo":16,"date":"2017-13-11 09:05:01","customerName":"Vikas","total":350.0,"fixedCharges":100,"taxAmount":25.78,"status":"paid","product":[{"productId":"MRR11","categoryId":72,"categoryName":"Parker Pen","cost":200,"quantity":2,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}},{"productId":"MRR12","categoryId":56,"categoryName":"Drawing Books","cost":150,"quantity":3,"log":{"supplierId":"725","supplierName":"Rihant General Stores"}}]}
' INTO json;
SELECT json->"$.product" INTO products;
WHILE i < JSON_LENGTH(products) DO
SELECT JSON_EXTRACT(products,CONCAT('$[',i,']')) INTO product;
SELECT product;
SELECT i + 1 INTO i;
END WHILE;
You'll probably need to do more than simply 'SELECT product' though ;-)
NOTE: MySQL JSON functions were added in 5.7.8 so you'll need to check your MySQL version first.
Extension to this answer, and if you want to loop through the keys of json object, you can do this via this way
declare _keys int default 0;
declare i int default 0;
declare _current_key varchar(50) default '';
select JSON_KEYS(product) into _keys;
while i < JSON_LENGTH(_keys) do
select json_extract(json_unquote(_keys), concat('$[', i, ']')) into _current_key;
set i = i + 1;
end while;