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;