MySQL IN Clause in SQL query with User Defined Function - mysql

I am using following query to update all the children of particular topic.
UPDATE topics SET reuse = 0 WHERE topic_id IN (SELECT GetChildTopics(187));
Where
SELECT GetChildTopics(187);
returns "188,190,189" but my update query is updating only first row with topic_id = 188, instead of updating first topic only, it should update all 3 topics.
When I put the values manually it works fine.
UPDATE topics SET reuse = 0 WHERE topic_id IN (188,190,189);
Can anyone suggest what's wrong I am doing here?
Here is the code for GetChildTopics MySQL Function
CREATE DEFINER=`root`#`localhost` FUNCTION `GetAncestry`(GivenID INT) RETURNS varchar(1024) CHARSET latin1
DETERMINISTIC
BEGIN
DECLARE rv VARCHAR(1024);
DECLARE cm CHAR(1);
DECLARE ch INT;
SET rv = '';
SET cm = '';
SET ch = GivenID;
WHILE ch > 0 DO
SELECT IFNULL(parent_topic_id,-1) INTO ch FROM
(SELECT parent_topic_id FROM topic_list WHERE id = ch) A;
IF ch > 0 THEN
SET rv = CONCAT(rv,cm,ch);
SET cm = ',';
END IF;
END WHILE;
RETURN rv;
END

Try this;)
UPDATE topics SET reuse = 0 WHERE FIND_IN_SET(topic_id, GetChildTopics(187));

Related

return null value in the JSON_EXTRACT

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

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

What does "The following query failed" ";"" mean in MySQL?

While trying to update a trigger, MySQL tells me the query ";" failed. How is ";" even a query in MySQL's view is beyond me.
The exact message is:
The following query has failed: ";" MySQL said: #1065 - Query was empty
Here's the new trigger (AFTER INSERT):
BEGIN
DECLARE vIdPlacet VARCHAR(40);
DECLARE vTypeTravaux VARCHAR(32);
DECLARE vEssence VARCHAR(3) DEFAULT '-';
DECLARE vClasseHau VARCHAR(5) DEFAULT '-';
DECLARE vNoMesurag int;
DECLARE new_id_parcelle INT UNSIGNED DEFAULT 0;
DECLARE new_no_microplacette INT UNSIGNED DEFAULT 0;
IF NEW.deleted = 0 THEN
SELECT id_parcelle, no_microplacette
INTO new_id_parcelle, new_no_microplacette
FROM microplacette
WHERE id_microplacette = NEW.id_microplacette;
SELECT travaux, no_mesurag, id__placet
INTO vTypeTravaux, vNoMesurag, vIdPlacet
FROM secteur
LEFT JOIN parcelle ON secteur.id_secteur = parcelle.id_secteur
WHERE id_parcelle = new_id_parcelle;
IF vTypeTravaux = 'inventaire' THEN
SELECT abbreviation INTO vEssence FROM essences WHERE _id = NEW.id_essence;
IF NEW.hauteur_15 = 1 THEN
SET vClasseHau = '15CM+';
END IF;
IF (SELECT COUNT(*) FROM imported_pres_ess WHERE id__placet = vIdPlacet AND
caracteris = '-' AND
classe_hau = vClasseHau AND
essence = vEssence AND
no_mesurag = vNoMesurag AND
no_micro_p = new_no_microplacette) = 0 THEN
INSERT INTO imported_pres_ess (id__placet, caracteris, classe_hau, essence, no_mesurag, no_micro_p)
VALUES (vIdPlacet, '-', vClasseHau, vEssence, vNoMesurag, new_no_microplacette);
END IF;
IF (SELECT COUNT(*) FROM imported_semi_gau WHERE id__placet = vIdPlacet AND
classe_hau = vClasseHau AND
essence = vEssence AND
no_mesurag = vNoMesurag AND
no_micro_p = new_no_microplacette) = 0 THEN
INSERT INTO imported_semi_gau (id__placet, classe_hau, essence, no_mesurag, no_micro_p)
VALUES (vIdPlacet, vClasseHau, vEssence, vNoMesurag, new_no_microplacette);
END IF;
IF NEW.diametre > 0 THEN
SET vClasseHau = 'D2_D8';
ELSE
SET vClasseHau = '-';
END IF;
IF (SELECT COUNT(*) FROM imported_pres_ess WHERE id__placet = vIdPlacet AND
caracteris = '-' AND
classe_hau = vClasseHau AND
essence = vEssence AND
no_mesurag = vNoMesurag AND
no_micro_p = new_no_microplacette) = 0 THEN
INSERT INTO imported_pres_ess (id__placet, caracteris, classe_hau, essence, no_mesurag, no_micro_p)
VALUES (vIdPlacet, '-', vClasseHau, vEssence, vNoMesurag, new_no_microplacette);
END IF;
IF (SELECT COUNT(*) FROM imported_semi_gau WHERE id__placet = vIdPlacet AND
classe_hau = vClasseHau AND
essence = vEssence AND
no_mesurag = vNoMesurag AND
no_micro_p = new_no_microplacette) = 0 THEN
INSERT INTO imported_semi_gau (id__placet, classe_hau, essence, no_mesurag, no_micro_p)
VALUES (vIdPlacet, vClasseHau, vEssence, vNoMesurag, new_no_microplacette);
END IF;
END IF;
END IF;
END
I tried creating the procedure you show, but I don't get any error.
The error about "empty statement" happens when you try to execute a query through the API but the query string is empty.
I can duplicate the error in the mysql client this way:
mysql> set #s = '';
mysql> prepare stmt from #s;
ERROR 1065 (42000): Query was empty
So I suggest you look not at the stored procedure, but whatever code you're executing this from, and check that every time you try to execute a query, that you submit a non-empty string.
It turns out, the trigger I was updating got deleted in the meantime, so I was updating a trigger that didn't exist anymore.
I found out after refreshing the page (the trigger was gone from the trigger list).
I simply recreated the trigger anew and it worked.

1172 - Result consisted of more than one row in mysql

How can I solve this problem (Result consisted of more than one row in mysql)
DROP PROCEDURE IF EXISTS `doMarksApplication`;
CREATE PROCEDURE `doMarksApplication`(
in kuser varchar(20),
out idpro int(11))
SP:BEGIN
declare no_more_rows int default FALSE;
declare total_marks decimal(10,2) default 0;
declare idfor int(11) default 0;
declare sskod int(5) default getCurSession();
declare bdata int(5) default 0;
declare nopmh varchar(20);
# Data PB [Permohonan Baru] DM [Proses Pemarkahan]
declare cur1 cursor for
select ind_nopmh from pinduk
left join pprses on pro_nopmh = ind_nopmh
where ind_sskod = sskod and
concat(pro_stats,pro_statp) in ('PB','DM') and
not exists (select mar_idnum from pmrkah where mar_nopmh = ind_nopmh)
order by ind_nopmh;
declare continue handler for not found set no_more_rows = TRUE;
begin
select count(ind_nopmh) into bdata
from pinduk
left join pprses on pro_nopmh = ind_nopmh
where ind_sskod = sskod and
concat(pro_stats,pro_statp) in ('PB','DM') and
not exists (select mar_idnum from pmrkah where mar_nopmh = ind_nopmh);
end;
begin
select count(for_idnum) into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg;
end;
if idfor = 1 and sskod <> 0 then
begin
select for_idnum into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg;
end;
begin
insert into pprmar
(pma_tkmla,pma_msmla,pma_puser,pma_sskod,pma_idfor,pma_bdata)
values
(curdate(),curtime(),kuser,sskod,idfor,bdata);
end;
begin
select last_insert_id() into idpro;
end;
open cur1;
LOOP1:loop
fetch cur1 into nopmh;
if no_more_rows then
close cur1;
leave LOOP1;
end if;
begin
call getMarksAnakPerak(nopmh,#total_perak);
call getMarksAkademik(nopmh,#total_akdmk);
call getMarksSosioekonomi(nopmh,#total_sosio);
end;
set total_marks = #total_perak + #total_akdmk + #total_sosio;
begin
insert into pmrkah
(mar_idpro,mar_nopmh,mar_idfor,mar_perak,mar_akdmk,mar_sosio,mar_total)
values
(idpro,nopmh,idfor,#total_perak,#total_akdmk,#total_sosio,total_marks);
end;
begin
update pprses
set pro_stats = 'D',
pro_statp = 'M',
pro_tkmsk = curdate(),
pro_msmsk = curtime(),
pro_kuser = kuser
where pro_nopmh = nopmh;
end;
end loop;
begin
update pprmar
set pma_tktmt = curdate(),
pma_mstmt = curtime()
where pma_idnum = idpro;
end;
end if;
END;
i have been programming in mysql for 15 years and this is easily the most confusing stored procedure i have ever seen.
None the less, one possible place for your issue is here
select for_idnum into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg;
I know it does not seem to be the reason but without knowing the content of the other three stored procedures you are calling this is the only candidate. You should add a limit 1 to it, and to every select into statement that reads from a table (i.e. not a sum() or a count() etc...) as that would always have the potential to cause the error you are seeing.
select for_idnum into idfor from xkod_markah_00_formula
where for_stats = 'A' and
curdate() between for_tkhdr and for_tkhhg limit 1;
In addition, you should comment out the three stored procedure calls and see if the error goes away. My guess is that the issue is one of those stored procedures due to a select into similar to above has more than one row in the result set but does not use limit 1 and does not filter properly.

Trigger syntax and IF ELSE THEN

I'd like to create a trigger which count the number of rows with a specific id (id_ort).
If it found more than 5 rows, I need to increment a variable.
Trigger Syntax
BEGIN
DECLARE nb INT;
DECLARE nba INT;
SET nba =0;
SET NEW.`VPLS_ID_NodeB` = CONCAT("21100", LPAD(NEW.`VPLS_ID_NodeB`,4,0));
SET nb = (SELECT COUNT(DISTINCT(`VPLS_ID_aggregation`)) FROM `VPLS_nodeB` WHERE `id_ORT` = NEW.`id_ORT`);
IF(nb > 5) THEN
SET nba = nb + 1;
ELSE
SET nba = nb;
END IF;
SET NEW.`VPLS_ID_aggregation` = CONCAT("21188", LPAD(NEW.`id_ORT`,2,0), LPAD(nba,2,0));
END
However, there is a bug... Even if i've less than 5 rows, the var is incremented each time.
Any ideas? Maybe it's a syntax problem...
Thanks a lot!
you probably forgot to specify a delimiter i've also made a few other changes as you can see
delimiter #
create trigger VPLS_nodeB_before_ins_trig before insert on VPLS_nodeB
for each row
BEGIN
DECLARE nb INT default 0;
DECLARE nba INT default 0;
SET NEW.VPLS_ID_NodeB = CONCAT('21100', LPAD(NEW.VPLS_ID_NodeB,4,0));
SET nb = (SELECT COUNT(DISTINCT(VPLS_ID_aggregation)) FROM VPLS_nodeB WHERE id_ORT = NEW.id_ORT);
IF(nb > 5) THEN
SET nba = nb + 1;
ELSE
SET nba = nb;
END IF;
SET NEW.VPLS_ID_aggregation = CONCAT('21188', LPAD(NEW.id_ORT,2,0), LPAD(nba,2,0));
END#
delimiter ;