MySQL trigger working on one table but not the other - mysql

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.

Related

user defined function in insert command

I created a function:
DELIMITER $$
DROP FUNCTION IF EXISTS `heena`.`customer_id`$$
CREATE DEFINER=`root`#`localhost` FUNCTION `heena`.`customer_id`(
a varchar(20),
b varchar(20)
) RETURNS varchar(50) CHARSET latin1
DETERMINISTIC
BEGIN
RETURN CONCAT(
(select ((id), 0) + 1
from heenaj),
substring(a,1,2),
substring(b,1,2));
END;$$
DELIMITER ;
The code executed fine, but when I'm inserting a value using:
insert into heenaj
(c_id,name,number)
values
(customer_id121("abcd",9868275817),"abcd",9868275817);
It shows an error:
Column 'c_id' cannot be null
There's something wrong with your RETURN.
Maybe you are meaning to do this, although I am only guessing:
RETURN CONCAT(
(select ifnull(max(id), 0) + 1
from heenaj),
substring(a,1,2),
substring(b,1,2));
sqlfiddle
Then, you're calling customerid121() not customer_id(). Could this be typo?
Also, in looking at what you're trying to do: do you want your id as auto_increment and just want to have c_id as the id, concatenated with first 2 characters of name and concatenated with first 2 characters of number?
I suggest another solution. It might be nicer to drop your function and create a TRIGGER for before INSERT, like this:
CREATE TRIGGER set_customer_id BEFORE INSERT on heenaj
FOR EACH ROW
BEGIN
SET NEW.c_id = CONCAT((SELECT IFNULL(MAX(id),0)+1 FROM heenaj),SUBSTRING(NEW.name,1,2),SUBSTRING(NEW.number,1,2));
END/
This way, when you insert you can just ignore c_id and insert like this:
insert into heenaj(name,number)
values ("abcd",9868);
The trigger will handle the setting of c_id for you.
sqlfiddle for TRIGGER
P.S. To create the trigger (in the sqlfiddle), I selected / as my delimiter. You might change that / to $$, since you're setting delimiter as $$.

Mysql said: #1422 - Explicit or implicit commit is not allowed in stored function or trigger

In the code below I'm trying to create a trigger which inserts 'incidentimg' table id along with an image path if the user of the web application did not upload a image with the form belonging to 'incidentreport' table, however, I'm only getting the error "MySQL said: #1422 - Explicit or implicit commit is not allowed in stored function or trigger"
DROP TRIGGER IF EXISTS `insertImage`;
CREATE TRIGGER `insertImage` AFTER INSERT ON `incidentreport`
FOR EACH ROW
BEGIN
IF(SELECT incidentimg.incidentImgId FROM incidentimg
LEFT JOIN incidentreport ON incidentimg.imgs_incidentReportId = incidentreport.incidentReportId
WHERE incidentimg.incidentImgId IS NULL)
THEN INSERT INTO incidentimg(incidentImgId, imgUrl)values(NEW.incidentReportId, 'images/no-image.png');
END IF;
END
;
Here are the tables being used
Can someone assist me on how to correct this problem
I finally got the code to work. Now the code will check whether 'incidentimg' table has all the 'incidentReportId' that the 'incidentreport' table has, and if it doesn't then the last inserted id from the 'incidentreport' table along with a default image path will be inserted into 'incidentimg' table AFTER INSERT.
CREATE TRIGGER insertImage AFTER INSERT ON incidentreport
FOR EACH ROW
BEGIN
IF(SELECT incidentreport.incidentReportId
FROM incidentreport
LEFT JOIN incidentimg ON incidentreport.incidentReportId = incidentimg.imgs_incidentReportId
WHERE incidentimg.imgs_incidentReportId IS NULL)
THEN INSERT INTO incidentimg(imgs_incidentReportId, imgUrl) VALUES(NEW.incidentReportId, 'images/no-image.png');
END IF;
END
I am not much sure but I am guessing that probably it's because of the IF .. THEN conditional INSERT. Try modifying your INSERT statement with an EXISTS like
DROP TRIGGER IF EXISTS `insertImage`;
CREATE TRIGGER `insertImage` AFTER INSERT ON `incidentreport`
FOR EACH ROW
BEGIN
INSERT INTO incidentimg(incidentImgId, imgUrl)
SELECT NEW.incidentReportId, 'images/no-image.png'
FROM DUAL WHERE EXISTS (
SELECT 1 FROM incidentimg
LEFT JOIN incidentreport
ON incidentimg.imgs_incidentReportId = incidentreport.incidentReportId
WHERE incidentimg.incidentImgId IS NULL
)
END;

Assigning the value from a select statement to a vairable in MySQL

I'm fairly new to SQL in general and even more so to MySQL and I've hit a stumbling block. I'm attempting to use a procedure to copy the value of one field to another if the original field is not null, this procedure is then called by triggers whenever the table is updated or has a new row inserted into it. Here is what I have so far:
-- WORK_NOTES_PROCEDURE - This copies the contents of the estimate notes to the work order notes if the original estimate had any notes with it.
DROP PROCEDURE IF EXISTS 'WORK_NOTES_PROCEDURE';
DELIMITER $$
CREATE PROCEDURE WORK_NOTES_PROCEDURE()
BEGIN
DECLARE var_temp VARCHAR(50);
SET var_temp := (SELECT ESTIMATE_NOTES FROM ESTIMATES WHERE ESTIMATES.ESTIMATE_NUMBER = WORK_ORDERS.ESTIMATE_NUMBER);
IF var_temp IS NOT NULL THEN
UPDATE WORK_ORDERS SET WORK_ORDER_NOTES = var_temp WHERE WORK_ORDERS.ESTIMATE NUMBER = ESTIMATES.ESTIMATE_NUMBER;
END IF;
END$$
DELIMITER ;
Absolutely any help would be appreciated, the error I'm getting is a syntax error for the line where I'm assigning a value to var_temp.
try,
SET var_temp = (SELECT ESTIMATE_NOTES
FROM ESTIMATES INNER JOIN WORK_ORDERS
ON ESTIMATES.ESTIMATE_NUMBER = WORK_ORDERS.ESTIMATE_NUMBER
LIMIT 1);

Weird issue with a stored procedure in MySQL

I need to add a new stored procedure on our company's MySQL server. Since it's just slightly different, I used an already existing one, added the additional field and changed the name of the procedure. The weird thing now is that when I want to execute the statement, it returns:
Error Code: 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 '' at line 3
reffering to the 0 in this line: SET #update_id := 0; What makes it weird is, that I queried that stored procedure by using SHOW CREATE PROCEDURE . It's saved in our database and is working fine. I just can't use it as a new stored procedure (no matter if I try to apply it to the new test database or if I use it on the existing database by giving it a new name).
I searched the internet for a solution. Unfortunately to no avail. I even set up a new database with a new table and some demo values where I tried to execute the original, unaltered stored procedure. It returns the exact same error.
Here's the currently used and working stored procedure I'm talking about:
CREATE DEFINER=`root`#`localhost` PROCEDURE `customer_getcard`(IN Iinstance INT, IN Itimebuy DOUBLE, IN Iprice DECIMAL(10,2), IN Itariff INT, IN Icomment VARCHAR(128))
BEGIN
SET #update_id := 0;
UPDATE customer_shop SET state = 1, id = (SELECT #update_id := id), instance=Iinstance, timebuy=Itimebuy, price=Iprice, comment=Icomment WHERE tariff=Itariff AND state = 0 LIMIT 1;
SELECT * FROM customer_shop WHERE id = #update_id;
END
I hope you guys can help me as I am completely out of ideas what's wrong. :/
Regards, Mark
You need to define an alternative command delimiter, as MySQL currently thinks your CREATE PROCEDURE command ends at the first ; it encounters (on line 3, after the 0), which would be a syntax error as it's after a BEGIN but before the corresponding END:
DELIMITER ;; -- or anything else you like
CREATE PROCEDURE
...
END;; -- use the new delimiter you chose above here
DELIMITER ; -- reset to normal
MySQL stored procedures do not use ":=" for value assignment, just use "=".
Also don't think "id = (SELECT #update_id := id)" is acceptable. Here's an alternative solution (untested):
CREATE DEFINER=`root`#`localhost` PROCEDURE `customer_getcard`(IN Iinstance INT, IN Itimebuy DOUBLE, IN Iprice DECIMAL(10,2), IN Itariff INT, IN Icomment VARCHAR(128))
BEGIN
select id into #update_id from customer_shop WHERE tariff=Itariff AND state = 0 LIMIT 1;
UPDATE customer_shop SET state = 1, instance=Iinstance, timebuy=Itimebuy, price=Iprice, comment=Icomment where id = #update_id;
SELECT * FROM customer_shop WHERE id = #update_id;
END
You may also want to put error handlers in case there's no matching row to be edited.

MySQL: IF / THEN statements in stored procedures

I'm writing a stored procedure that uses multiple IF / THEN statements that also need to execute multiple queries if they evaluate to true. Problem is, I can't seem to find any examples of the appropriate syntax. From the MySQL dev handbook, it seems like I could have multiple queries in the "statement_list," but so far I can't get it to work.
Here's what I'm trying to do:
SET agency =
COALESCE((SELECT org_agency_o_id
FROM orgs_agencies
WHERE org_agency_code = maj_agency_cat)
,(SELECT min(org_id)
FROM orgs
WHERE org_name LIKE CONCAT('U.S.',SUBSTRING(maj_agency_cat,5))))
IF agency IS NULL THEN
-- execute multiple queries
INSERT INTO orgs (org_name
,org_name_length
,org_type
,org_sub_types)
VALUES (CONCAT('U.S. ',SUBSTRING(maj_agency_cat,5))
,LENGTH(CONCAT('U.S. ',SUBSTRING(maj_agency_cat,5)))
,'org','Org,GovernmentEntity,Federal,Agency');
SET agency = LAST_INSERT_ID();
END IF;
The error:
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 'IF agency IS NULL THEN
INSERT INTO orgs (org_name,org_name_length,org_type,' at line 53
Any ideas? I know it has to be something simple, so I would greatly appreciate anybody's input.
You got a few issues as far as I can see:
As David pointed out, each and every statement needs to be terminated by a ;
If you do a SELECT, better make sure it can only select one value by doing a LIMIT 1; If you've got an aggregate function like min() then only one value can come out.
If you writing the procedure using the CREATE PROCEDURE ... syntax, don't forget to set DELIMITER $$ before the CREATE PROCEDURE ... END $$ body and a DELIMITER ; after.
If you have multiple statements inside your IF THEN ... END IF block, it's a good idea to put them inside a BEGIN ... END; block.
If you have a return value, like agency here, why not make it a FUNCTION name (arg1: INTEGER) RETURNS INTEGER instead of a PROCEDURE name (IN arg1 INTEGER, OUT agency INTEGER). The function is much more versatile.
DELIMITER $$
CREATE PROCEDURE name(arg1 INTEGER, arg2 INTEGER, ...)
BEGIN
SELECT SET agency =
COALESCE((SELECT org_agency_o_id
FROM orgs_agencies
WHERE org_agency_code = maj_agency_cat) LIMIT 1,
(SELECT min(org_id) FROM orgs
WHERE org_name LIKE CONCAT('U.S.',SUBSTRING(maj_agency_cat,5))));
IF agency IS NULL THEN BEGIN
-- execute multiple queries
INSERT INTO orgs (org_name
,org_name_length
,org_type
,org_sub_types)
VALUES (CONCAT('U.S. ',SUBSTRING(maj_agency_cat,5))
,LENGTH(CONCAT('U.S. ',SUBSTRING(maj_agency_cat,5)))
,'org','Org,GovernmentEntity,Federal,Agency');
SET agency = LAST_INSERT_ID();
END; END IF;
END $$
DELIMITER ;
No semicolon after your first SET statement.