passing json in stored procedures - mysql
I am calling a stored procedure and it is giving a syntax error, I am unable to figure it out. Can anyone help?
"sqlMessage": "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 '\"billToId\":137,\"shipToId\":137,\"loadingId\":137,\"loadingLocationId\":2,\"billToLocat' at line 1",
It is a JSON that I am passing as a string.
Here's the stored procedure:
drop procedure if exists createRequisition;
DELIMITER $$
CREATE PROCEDURE createRequisition(p_reqBranchId INT,p_unloadingJson JSON,locationsString text,p_quantity FLOAT,
p_expectedDeliveryDate DATE,p_loadingDate DATE,p_refId VARCHAR(255),p_notes TEXT,p_createdBy VARCHAR(255),p_vehicleId INT, p_vehicleName VARCHAR(255),p_isWeb int,p_priority int,p_editId int)
BEGIN
-- call SP_TMS_CreateRequisition()
declare lastReqCode int;
declare d_ReqCode text;
declare d_branchCode text;
declare lastInsert INT;
declare d_branchIdsStr text;
START transaction;
if(p_editId is null) then
BEGIN
SET d_branchCode = (select group_concat(freighterCode) from Freighters join Branches on freighterId = branchFreighterId where branchId = p_reqBranchId);
SET d_branchIdsStr = (select group_concat(branchId) from Branches where branchFreighterId = (select branchFreighterId from Branches where branchId = p_reqBranchId) );
SET lastReqCode = (SELECT if(max(CAST(substring(reqCode,5) AS UNSIGNED))>0,max(CAST(substring(reqCode,5) AS UNSIGNED)),0) FROM Requisitions where find_in_set(reqBranchId,d_branchIdsStr));
set d_ReqCode = (select concat(d_branchCode,lastReqCode+1));
INSERT INTO Requisitions(reqCode,reqBranchId,vehicleId,vehicleName,loadingUnloadingJson,quantity,originalQuantity,deliveryDate,loadingDate,referenceNumber,notes,createdAt,createdBy,updatedAt,reqIsWeb,priority)
VALUES(d_ReqCode,p_reqBranchId,p_vehicleId, p_vehicleName,p_unloadingJson,p_quantity,p_quantity,p_expectedDeliveryDate,p_loadingDate,p_refId,p_notes,NOW(),p_createdBy,NOW(),p_isWeb,p_priority);
set lastInsert = (SELECT LAST_INSERT_ID());
set locationsString = replace(locationsString,'reqId',lastInsert);
set #reqLocationInsert = concat('INSERT INTO RequisitionDetails (requisitionId,billToBranchId,shipToBranchId,loadingBranchId,loadingLocationId,billToLocationId,shipToLocationId,skuId,skuQuantity,skuWeight,requisitionJson) VALUES',locationsString);
PREPARE stmt from #reqLocationInsert;
EXECUTE stmt;
select lastInsert as reqId;
END;
else
BEGIN
UPDATE `Requisitions`
SET
`vehicleId` = p_vehicleId,
`vehicleName` = p_vehicleName,
`loadingDate` = loadingDate,
`referenceNumber` = p_refId,
`notes` = p_notes,
`updatedAt` = now(),
`updatedBy` = p_createdBy,
`priority` = p_priority
WHERE `reqId` = p_editId;
DELETE from RequisitionDetails where requisitionId = p_editId;
set #reqLocationInsert = concat('INSERT INTO RequisitionDetails (requisitionId,billToBranchId,shipToBranchId,loadingBranchId,loadingLocationId,billToLocationId,shipToLocationId,skuId,skuQuantity,skuWeight,requisitionJson) VALUES',locationsString);
PREPARE stmt from #reqLocationInsert;
EXECUTE stmt;
select lastInsert as reqId;
END;
end if;
COMMIT;
END
And the parameters that I am passing is:
call createRequisition(5,null,'(reqId,137,137,137,2,2,2,493,{\"billToId\":137,\"shipToId\":137,\"loadingId\":137,\"loadingLocationId\":2,\"billToLocationId\":2,\"shipToLocationId\":2,\"skuId\":493,\"skuWeight\":30,\"loadingbranchName\":\"New Branch \",\"loadingCompanyName\":\"Teja & Teja Pvt. Ltd\",\"loadingErpCode\":\"WERT\",\"loadingShortName\":\"Kolkata\",\"loadingLongName\":\"West Bengal, India\",\"shipToCompanyName\":\"Teja & Teja Pvt. Ltd\",\"shipTobranchName\":\"New Branch \",\"shipToErpCode\":\"WERT\",\"shipToShortName\":\"Kolkata\",\"shipToLongName\":\"West Bengal, India\",\"billToBranchName\":\"New Branch \",\"billToCompanyName\":\"Teja & Teja Pvt. Ltd\",\"billToErpCode\":\"WERT\",\"billToShortName\":\"Kolkata\",\"billToLongName\":\"West Bengal, India\",\"skuQuantity\":10})',
10,null,'2019-10-18',
'111','Just Do It',
'17',2,
'Open Daala zzz',1,'HIGH',null)
Related
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.
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.
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.
MySQL stored procedure INSERT issue
The following scenario applies: CREATE TEMPORARY TABLE IF NOT EXISTS `smth_table` ( `login` VARCHAR(20), `password` VARCHAR(20), `type` INT(11), `account_state` DECIMAL(12,4) ); PREPARE Selection FROM "INSERT INTO `smth_table` (SELECT ta.`login`, ta.`password`, ta.`type`, ta.`account_state` FROM tableA ta INNER JOIN tableB tb ON tb.id_client = ta.id_client WHERE tb.id_lot = ? AND ta.`type` MOD 2 = 0 AND ta.first_use = '0000-00-00 00:00:00' AND ta.account_state = 0 LIMIT ?)"; SET #WHERE = var1; SET #LIMIT = var2; EXECUTE Selection USING #WHERE, #LIMIT; DEALLOCATE PREPARE Selection; DECLARE curs CURSOR FOR SELECT `password` FROM `smth_table`; DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_finished = 1; OPEN pin_curs; get_pass: LOOP FETCH curs INTO pass; IF v_finished = 1 THEN LEAVE get_pass; END IF; UPDATE tableA ta INNER JOIN tableB tb ON tb.id_client = ta.id_client SET `type` = `type` | 1, `account_state` = `account_state` + 5 WHERE tb.id_lot = var1 AND `password` = pass; END LOOP get_pass; CLOSE curs; END Why, when I run this stored procedure, does the temp table populates with more then the limit? Keep in mind that I set the LIMIT with an IN variable passed through the procedure, and it's 10, incidentally. But when I run the procedure it inserts in the temp table more the 100 rows, and I don't understand why, when it should insert only 10.
SOLVED! The issue relayed on the fact that I was not deleting the table upon creating it again, thus inserting same values over and over again... DROP TABLE IF EXISTS `smth_table`; this inserted before creating it and the query's run smooth :-)
Asking about stored function in mysql
drop function if exists rty_check_member_info_status; DELIMITER $$ -- -- Functions CREATE DEFINER=root#localhost FUNCTION rty_check_member_info_status(memb_id int,field_name_1 varchar(100),field_name_2 varchar(100),login_member_amount int(11),login_status char(1)) RETURNS char(1) CHARSET latin1 begin declare fn_field_name_1 varchar(100) ; declare fn_field_name_2 varchar(100) ; declare fn_amount_for_profile_visible int(11); declare fn_return char(1) default 'N'; declare test_field varchar(100); select field_name_1,field_name_2,amount_for_profile_visible into fn_field_name_1,fn_field_name_2,fn_amount_for_profile_visible from member_account_settings inner join tbl_members on member_account_settings.member_auto_id = tbl_members.member_id where tbl_members.member_id = memb_id ; if fn_field_name_1 = 'H' Then set fn_return = 'N' ; else if fn_field_name_2 = 'Y' Then if fn_amount_for_profile_visible = '0' Then set fn_return = 'Y' ; else if login_status = 1 Then if fn_amount_for_profile_visible > login_member_amount Then set fn_return = 'N' ; else set fn_return = 'Y' ; end if; else set fn_return = 'N'; end if ; end if; else set fn_return = 'Y'; end if ; end if ; return fn_return ; end$$ DELIMITER ;
You're two choices are pretty much generated SQL(normally a bad idea because it's harder to write, debug and document) and using a case statement to select the column based on the name matching a string(which is normally a pretty good solution). Here's an example of the second, since it's the solution I'd definitely recommend. SET #test_field1 = "last_name_display_status" ; SET #test_field2 = "last_name_display_for_other_partcpnt" ; SELECT CASE #test_field1 -- List columns here that you might want to return: WHEN 'last_name_display_status' THEN last_name_display_status WHEN 'last_name_display_for_other_partcpnt' THEN last_name_display_for_other_partcpnt WHEN 'create_date' THEN create_date -- Return a value for an invalid name here: ELSE NULL END AS test_field1, CASE #test_field2 -- List columns here that you might want to return: WHEN 'last_name_display_status' THEN last_name_display_status WHEN 'last_name_display_for_other_partcpnt' THEN last_name_display_for_other_partcpnt WHEN 'create_date' THEN create_date -- Return a value for an invalid name here: ELSE NULL END AS test_field2, -- Rest of select unaffected by this change amount_for_profile_visible INTO fn_field_name_1, fn_field_name_2, fn_amount_for_profile_visible FROM member_account_settings INNER JOIN tbl_members ON member_account_settings.member_auto_id = tbl_members.member_id WHERE tbl_members.member_id = memb_id ; And for the sake of completeness a copy of the first solution I proposed(the generated SQL): -- Need to use #vars, since named vars aren't in scope for the generated SQL: SET #output1 = ''; SET #output2 = ''; SET #output3 = ''; SET #input1 = memb_id; -- We also need to store our generated SQL to a variable SET #query = 'SELECT ' + #test_field1 + ',' + #test_field2 + ', amount_for_profile_visible INTO #output1, #output2, #output3 FROM member_account_settings INNER JOIN tbl_members ON member_account_settings.member_auto_id = tbl_members.member_id WHERE tbl_members.member_id = ?'; -- To execute the code we have to convert it to a prepared statement -- named stmt here, because it's what most people use in this instance PREPARE stmt FROM #query; -- Execute the statement using our input variable EXECUTE stmt USING #input1; -- Delete the prepared statement now we've run it. DEALLOCATE PREPARE stmt; -- Store our #vars back into the named vars. SET fn_field_name_1 = #output1; SET fn_field_name_2 = #output2; SET fn_amount_for_profile_visible = #output3;