Mysql stored procedure SQLEXCEPTION - mysql

Below is my sample query, in which 1st create new folder,2nd update count, 3rd: create new tag, 4: get new id.all query are executed in same stored procedure.in which #pFolderId is the id passed by user(in parameter),
foreign key constraint are applied on folderId of tag table, when user sends valid folderId, it executes properly & i get new tagid, but when user sends invalid folderid which is not exists in folder table, then it throws exception of foreign key. but in this case 1st,2nd query is alredy executed, 3rd query gives error. my question is how to avoid query from execution on any error on any query. 1 way is to use roolback, but when i used that it execute properly for 1 invalid folder request, but when on 2nd request it executed 1,2 query and gave error on 3rd.
1: insert into folder (name)values("new");
2: update folder set count = count + 1 where idfolder=1;
3: insert into tag(name,folder_Id)values("dsdss",#pFolderId );
4: SELECT last_insert_id() AS tag_id;
how can i achieve this, avoid execution on error.any help will be appreciated. thank you in advance.
PROCEDURE:
DELIMITER $$
CREATE DEFINER=root#localhost PROCEDURE newClip(pFolderId VARCHAR(100))
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION,SQLWARNING
BEGIN
SELECT SQLEXCEPTION.message;
ROLLBACK;
END;
SET #pFolderId = pFolderId;
START TRANSACTION;
insert into folder (name)values("new");
update folder set count = count + 1 where idfolder=1;
insert into tags(name,folderId)values("dsdss",#pFolderId );
SELECT last_insert_id()AS tag_id;
COMMIT;
END$$

Related

MySQL PROCEDURE using IF Statement with #Parameter Not Working

Why is the data not being inserted on the table when I execute the procedure, what seems to be lacking with the code?
I'm testing the procedure on phpMyAdmin > myDatabase > Procedures "Routines Tab" and clicking "Execute", prompts with a modal and ask for the values of "#idproc and #nameproc.
I tried with just the INSERT code it works, but when I add the IF condition it doesn't work.
Using XAMPP 8.0.3,
10.4.18-MariaDB
DELIMITER $$
CREATE DEFINER=`root`#`localhost:3307` PROCEDURE `testproc`(IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF #idproc = 0 THEN
INSERT INTO testproc(
id,
name)
VALUES(
#idproc,
#nameproc
);
ELSE
UPDATE testproc
SET
id = #idproc,
name = #nameproc
WHERE id = #idproc;
END IF;
SELECT * FROM testproc;
END$$
DELIMITER ;
You mix local variables (their names have not leading #) and user-defined variables (with single leading #). This is two different variable types, with different scopes and datatype rules. Procedure parameters are local variables too.
So when you use UDV which was not used previously you receive NULL as its value - and your code works incorrectly. Use LV everywhere:
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
IF idproc = 0 THEN
INSERT INTO testproc (name) VALUES (nameproc);
ELSE
UPDATE testproc SET name = nameproc WHERE id = idproc;
END IF;
SELECT * FROM testproc;
END
You do not check does specified idproc value exists in the table. If it is specified (not zero) but not exists then your UPDATE won't update anything. Assuming that id is autoincremented primary key of the table I recommend to use
CREATE DEFINER=`root`#`localhost:3307`
PROCEDURE `testproc` (IN `idproc` INT, IN `nameproc` VARCHAR(100))
BEGIN
INSERT INTO testproc (id, name)
VALUES (idproc, nameproc)
ON DUPLICATE KEY
UPDATE name = VALUES(name);
SELECT * FROM testproc;
END
If specified idproc value exists in id column the row will be updated, if not then the new row will be inserted.
Additionally - I recommend you to provide NULL value instead of zero when you want to insert new row with specified nameproc value. NULL always cause autoincremented primary key generation whereas zero needs in specific server option setting.

SQL Event - DELETE AND UPDATE rows on tables after UPDATE other table

I'd like to have a tricky SQL statement as an Event that runs every couple of minutes.
Currently, I'm doing so with Java, using 3 separate statements that executing sequentiality in a transaction connection.
Q: I don't know how to construct such an SQL statement without Java. If impossible to have a single SQL statement, I'd like to use transaction (as I'm using in Java) and rollback in case of failure in any of those separate statements.
My Case:
I have 3 tables: "Factory", "Plan", "Machine".
I want to do something as below:
1.
WHERE Machines.annualCheck == "TRUE"
SET Machine.status = "IN_ANNUAL_CHECK"
For machines that got updated I need to do the following:
2.1 Update the related factory
WHERE Factory.id == Machine.linkFactoryID
UPDATE Factory.totalActiveMachines = --1
2.2 Delete the upcoming plans that planned to be handled by the related machine
DELETE rows WHERE Plan.willHandleByMachineID = Machine.ID
p.s. I'm using MySQL
Thank you!
Update:
In following to Simonare suggestion, I tired to do the following:
DELIMITER $
CREATE PROCEDURE annualCheck(IN Machine_ID int, IN Factory_ID int)
BEGIN
UPDATE machine_table
SET machine_table.annualCheck = 'IN_ANNUAL_CHECK'
WHERE machine_table.machine_id = Machine_ID;
UPDATE factory_table
SET factory_table.totalActiveMachines = factory_table.totalActiveMachines - 1
WHERE factory_table.factory_id = Factory_ID;
DELETE FROM plan_table WHERE plan_table.assign_to_machine = Machine_ID
END$
DELIMITER $$
BEGIN
SELECT #m_id = machine_id, #f_id = link_factory_id
FROM machine_table
WHERE machine_table.annualCheck = 'TRUE';
END$$
CALL annualCheck(#m_id,#f_id)
I don't know why, but I'm running into syntax errors - one after the other.
It's my first time to use PROCEDURE and DELIMITER. Am I doing it right?
you can use stored procedure
delimiter //
CREATE PROCEDURE myProc (IN Machine_ID int)
BEGIN
UPDATE myTable
SET Machine.status = "IN_ANNUAL_CHECK"
WHERE Machines.annualCheck == "TRUE";
Update the related factory
WHERE Factory.id == Machine.linkFactoryID
UPDATE Factory.totalActiveMachines = totalActiveMachines -1;
DELETE FROM Plan WHERE Plan.willHandleByMachineID = Machine_ID;
END//
then you can execute it either from mysql
CALL simpleproc(#a);
or from Java
It is also possible to create trigger on the Machine table, something like this:
CREATE TRIGGER `TRG_Machines_AfterUpdate` AFTER UPDATE ON `Machine` FOR EACH ROW BEGIN
IF OLD.annualCheck = 'TRUE' AND NEW.annualCheck = 'IN_ANNUAL_CHECK' THEN
UPDATE
Factory
SET
totalActiveMachines = totalActiveMachines - 1
WHERE
id = NEW.linkFactoryID
;
DELETE FROM
Plan
WHERE
willHandleByMachineID = NEW.ID
;
END;
END
So you can just issue normal update:
UPDATE Machine SET annualCheck = 'IN_ANNUAL_CHECK' WHERE annualCheck = 'TRUE'

'RAISERROR' must be declared

CREATE TRIGGER x AFTER INSERT ON itemtype
FOR EACH ROW
DECLARE
minn itemtype.PRICE%type;
BEGIN
select MIN(itemtype.PRICE) into minn from itemtype;
IF (:new.PRICE > minn*4) then RAISERROR('Custom text');
END IF;
END;
/
I'm trying to create a trigger that raises an error when I try to insert a new entry into the itemtype with itemtype.PRICE column value is greater than 4 times the current low priced item on the table.
I get these compilation errors when I try to create the trigger.
LINE/COL ERROR
-------- --------------------------------------------------------------
5/31 PL/SQL: Statement ignored
5/31 PLS-00201: identifier 'RAISERROR' must be declared
I have also tried
CREATE TRIGGER x AFTER INSERT ON itemtype
FOR EACH ROW
DECLARE
minn itemtype.PRICE%type;
BEGIN
select MIN(itemtype.PRICE) into minn from itemtype;
if (:new.PRICE > minn*4) then raise_application_error(-20010,'Too Expensive');
END IF;
END;
/
which complies, but when i try to insert a new entry into the table I get theses errors saying my trigger fails.
SQL> insert into itemtype(ITEMNUM,NAME,PICTURE,PRICE,BELONGSTO ) VALUES ('A11','The who knows','',10.99,'P');
insert into itemtype(ITEMNUM,NAME,PICTURE,PRICE,BELONGSTO ) VALUES ('A11','The who knows','',10.99,'P')
*
ERROR at line 1:
ORA-04091: table USERNAME.ITEMTYPE is mutating, trigger/function may not see it
ORA-06512: at "USERNAME.X", line 5
ORA-04088: error during execution of trigger 'USERNAME.X'
Try use PRAGMA AUTONOMOUS_TRANSACTION in trigger.
Look my answer on this question:
SQL trigger on delete mutating table

Third-party stored procedure returns value on select and it stops my own stored procedure

I'm designing a Stored Procedure which does a lot of things, some of them covered for third-party SPs that I cannot edit because they're hugely used on other places of the app I'm developing. I'll simplify my code in order to explain my problem a little easier:
My code is the following:
DELIMITER ;;
CREATE PROCEDURE `my_own_sp`(
IN my_param INT(11),
OUT my_returned_value INT(11),
OUT logger TEXT
)
BEGIN
SET logger = "echo off";
CALL third_party_SP(my_param);
SET logger = "half way!";
CALL another_third_party_SP(my_param);
SELECT id_user INTO my_returned_value FROM main_Table WHERE id_param = my_param;
SET logger = "This is the end...";
END;;
DELIMITER ;
both third party SPs would be like the following, they don't return any value but they modify some tables and records and then they make a SELECT in order to receive the result in PHP:
DELIMITER ;;
CREATE PROCEDURE `third_party_SP`(
IN my_param INT(11)
)
BEGIN
-- Do a lot of magic between tables
SELECT * FROM secondary_table WHERE id_param = my_param;
END;;
DELIMITER ;
But when I execute my SP, instead of receiving the value of my_returned_param and logger = "This is the end...", I receive the select of third_party_SP (I'm not even receiving logger = "half way!". It seems to me that the execution of my_own_sp stops once it receives a returned value, but this value is the last select of third_party_SP.
So the question is: can I handle the returned select of third_party_SP so I can keep working? or maybe there's another way to call third_party_SP in order to avoid the returned select?
Thank you very very much

MySQL trigger working on one table but not the other

I have created a mysql trigger to update on insert a value from another table:
DROP TRIGGER IF EXISTS `CourseCode`//
CREATE TRIGGER `CourseCode` BEFORE INSERT ON `race`
FOR EACH ROW BEGIN
SET NEW.Course_Code = (
SELECT
course_code
from
tb_course
where
tb_course.course_name = NEW.course_name
)
END
//
This works perfectly. It returns the 4 character code for the course_name based on the tb_course table.
What I'm trying to do is the exact same thing in another table, I copy and paste the trigger and rename the trigger and the table (field names and types are also identical) it but it won't work:
DROP TRIGGER IF EXISTS `CourseCode2`//
CREATE TRIGGER `CourseCode2` BEFORE INSERT ON `fields`
FOR EACH ROW
BEGIN
SET NEW.Course_Code = (
SELECT
course_code
from
tb_course
where
tb_course.course_name = NEW.course_name
)
END
//
However this results in null values. I've tried replacing New.Course_name with a string (i.e. tb_course.course_name="String") and that updates that static value fine so the trigger appears to be working but either it isn't matching the select statement in this table for or it's not setting the Course_Code field...
Is there any sort of debugging you can suggest to figure this out? It's driving me nuts and I don't know what to do to diagnose the problem.
Cheers
I have no idea what is wrong with the second trigger.
However, the 'debugging' part i can maybe help with.
A search of the 'net' will return various software (paid for) that will allow single step debugging. Rather than pay for stuff, all i want is 'print' statements from inside stored function procedures and triggers.
a quick search lead me to someone who has done all the work already.
Debugging Stored Procedures in MySql
I have just set it up in MySql and tried it and it works fine.
Here is some sample code, based on your trigger and the output i got.
DELIMITER $$
USE `testmysql`$$
DROP TRIGGER /*!50032 IF EXISTS */ `CourseCode`$$
CREATE
/*!50017 DEFINER = 'test'#'localhost' */
TRIGGER `CourseCode` BEFORE INSERT ON `race`
FOR EACH ROW BEGIN
DECLARE v_course_code INT;
DECLARE v_course_title VARCHAR(255);
CALL procLog("line 12: Entering CourseCode");
SELECT
course_code, course_title
INTO
v_course_code, v_course_title
FROM
tb_course
WHERE
tb_course.course_name = NEW.course_name;
SET NEW.course_code = v_course_code;
CALL procLog(CONCAT("line_22: ", v_course_title, " code: ", NEW.course_code));
CALL procLog("line 24: Exiting CourseCode");
END;
$$
DELIMITER ;
Query:
CALL setupProcLog();
INSERT INTO `race` (course_name, race_info)
VALUES ('learn_it_02', 'this is another test');
CALL cleanup('query end');
procLog output:
entrytime connection_id msg
2014-02-23 12:32:21 5 line 12: Entering CourseCode
2014-02-23 12:32:21 5 line_22: Learn It Course 02 code: 2
2014-02-23 12:32:21 5 line 24: Exiting CourseCode
2014-02-23 12:32:21 5 cleanup() query end
Ok, a little clumsy maybe but it will help with debugging 'stored' programs.
I will be using it from now on.