mysql trigger using custom function - mysql

I am trying to write a MySQL trigger that, upon update of a row, will call a custom function (which works fine outside of the trigger) and update a column in the table the trigger is on.
BEGIN
UPDATE candles
SET can_materials_cost = (SELECT calculateMaterialCost(NEW.can_id)
WHERE candles.can_id = NEW.can_id);
END
I've written basic audit style triggers that upon update save the old value into a different table, but for some reason when trying to use my custom function I receive an error stating:
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 'WHERE candles.can_id = NEW.can_id);
END' at line 4
The custom function performs:
BEGIN
-- This function assumes that the raw wax cost is for 20kg bags only - BEWARE!
DECLARE result DECIMAL(10,2);
SET result = (
(select calculateWaxCost(_can_id))
+
(select calculateDyeCost(_can_id))
+
(select calculateScentCost(_can_id)));
RETURN result;
END

Related

MySQL trigger is producing a syntax error, but I'm not sure what is wrong with it

I've created a trigger to update one table once an item is inserted into another. The trigger will also check one of the values being inserted into the new table, and using an if/elseif, will perform the appropriate Update query. I'm running in to a syntax error, but I'm not sure what's wrong with my syntax
CREATE TRIGGER Create_Media_Like_Trigger AFTER INSERT ON MediaLike
FOR EACH ROW
IF NEW.likeType = 'LIKE' THEN
UPDATE Media
SET Media.numLikes = Media.numLikes + 1
WHERE Media.mediaId = NEW.mediaId
ELSEIF NEW.likeType = 'DISLIKE' THEN
UPDATE Media
SET Media.numLikes = Media.numLikes - 1
WHERE Media.mediaId = NEW.mediaId
END IF;
I'm receiving an syntax error on or near the ELSEIF line, but I cant figure out what is wrong with it

MySQL syntax error while creating a UPDATE Trigger

I am trying to create a trigger on updating the salary field of this table.
customers(ID, Name, Age, Address, Salary) from this site SQL Trigger
While creating it shows the following error
MySQL said:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'OR INSERT OR UPDATE ON customers
FOR EACH ROW
WHEN (NEW.ID > 0)
DECLARE
' at line 2
Here is the code snippet:
BEFORE DELETE OR INSERT OR UPDATE ON customers
FOR EACH ROW
WHEN (NEW.ID > 0)
DECLARE
sal_diff number;
BEGIN `enter code here`
sal_diff := :NEW.salary - :OLD.salary;
dbms_output.put_line('Old salary: ' || :OLD.salary);
dbms_output.put_line('New salary: ' || :NEW.salary);
dbms_output.put_line('Salary difference: ' || sal_diff);
END
Note that, I'm using phpMyAdmin. Does dbms_ouput.put_line() works there?
As said in the comments, you are using Oracle syntax, it can't work on MySQL.
Then, there's no reason to have this trigger on DELETE and INSERT because your aim is to compute the salary difference on a specific row before and after it get updated. You can't have a value NEW on DELETE, and you can't have a value OLD on INSERT.
Thus your computation is only meaningful on UPDATE.
Here's the correct MySQL syntax (I am assuming that you have a column sal_diff on your table)
DELIMITER $$
CREATE TRIGGER `update_sal_diff`
BEFORE UPDATE ON `customers `
FOR EACH ROW
BEGIN
SET NEW.sal_diff = NEW.salary - OLD.salary;
END $$
DELIMITER ;
If this is not what you are trying to achieve, edit your question and add clear requirements

MySQL - phpmyadmin - swap columns

I try swap 3 columns in my table. I try this :
DELIMITER $$
CREATE PROCEDURE px()
BEGIN
DECLARE temp VARCHAR(20);
update `idsaccess` set
temp = referer,
referer = size_var,
size_var = agent,
agent = temp
WHERE agent like '%210%' ;
END $$
CALL p
It don't work. It give me that error: Unknown column 'temp' in 'field list' I do not understand that: temp is varchar value not a column. I also try remove DECLARE and PROCEDURE and just set variable with #. Like this:
set #temp = '';
update `idsaccess`
set #temp = referer,
referer = size_var,
size_var = agent
agent = #temp
WHERE agent like '%210%'
It don't work either. It give me. You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax. Any idea what is wrong in my code ? And to avoid misunderstanding I don't want move columns. I just want swap SOME rows (WHERE agent like '%210%') from one column to another.
Try this after taking a backup... I tried for table I have with 2 columns and worked
UPDATE idsaccess SET referer=#tmp:=referer, referer=size_var, size_var = agent, agent = #tmp WHERE agent like '%210%';

syntax error in create trigger, what's wrong?

can somebody tell me what is wrong with the syntax of my code please? (this is the exact and only code I'm highlighting and running so line numbers should match up)
CREATE TRIGGER `trg_part_upd` AFTER UPDATE ON `tbl_sub_model_eng_trans_part`
FOR EACH ROW
if NEW.engine_sk = 0 and NEW.trans_sk = 0
then
UPDATE tbl_sub_model tsm
INNER JOIN tbl_fct_sub_eng_trans tfset ON tsm.sub_model_sk = tfset.sub_model_sk
INNER JOIN tbl_sub_model_eng_trans_part tsmetp ON tfset.trans_sk = tsmetp.trans_sk
SET tsm.last_modified_date = NOW()
WHERE tsmetp.sub_model_sk=NEW.sub_model_sk;
end if;
I get these two errors:
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 9
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 'end if' at line 1
You forgot to change the delimiter, so MySQL thinks your first statement is this:
CREATE TRIGGER `trg_part_upd` AFTER UPDATE ON `tbl_sub_model_eng_trans_part`
FOR EACH ROW
if NEW.engine_sk = 0 and NEW.trans_sk = 0
then
UPDATE tbl_sub_model tsm
INNER JOIN tbl_fct_sub_eng_trans tfset ON tsm.sub_model_sk = tfset.sub_model_sk
INNER JOIN tbl_sub_model_eng_trans_part tsmetp ON tfset.trans_sk = tsmetp.trans_sk
SET tsm.last_modified_date = NOW()
WHERE tsmetp.sub_model_sk=NEW.sub_model_sk;
Just add this before the code:
DELIMITER $$
... and this afterwards:
$$
... so MySQL can recognize the complete trigger as a single statement.
You can change $$ for your own choice.
Official docs give details on this in the Defining Stored Programs section.
Please note that this issue only affects MySQL clients that can accept more than one statement at once so they implement a separator to tell them apart. DELIMITER is a command of the mysql command-line tool; it may or may not be implemented in other clients.
Try This:
DELIMITER $$
CREATE TRIGGER `trg_part_upd` AFTER UPDATE ON `tbl_sub_model_eng_trans_part`
FOR EACH ROW BEGIN
IF NEW.engine_sk = 0 AND NEW.trans_sk = 0
THEN
UPDATE tbl_sub_model tsm
INNER JOIN tbl_fct_sub_eng_trans tfset ON tsm.sub_model_sk = tfset.sub_model_sk
INNER JOIN tbl_sub_model_eng_trans_part tsmetp ON tfset.trans_sk = tsmetp.trans_sk
SET tsm.last_modified_date = NOW()
WHERE tsmetp.sub_model_sk=NEW.sub_model_sk;
END IF;
END;
$$
DELIMITER ;
The trigger is a source object, it has a body - one or more internal statements.
If there are some statements in body, then body must be wrapped with BEGIN...END clause. In this case you may also need to use client DELIMITER command for the CREATE TRIGGER.
If you had one statement in the body, then you could use syntax without BEGIN...END, and without DELIMITER command.

Creating a database function within Magento for a module

I have a working module in Magento that is modeled after some custom code we use outside of our install. This module currently add 5 tables to the database to store info and I have extended the Admin to CRUD the info. The ultimate goal here is to move the majority of this custom programming into Magento.
Currently our custom code sits outside Magento and hits a separate database. This database has those same 5 tables, a stored procedure, and 4 functions. What I would like to do now is move the stored procedures and the functions into Magento's database and change the custom code to call all of it's data from Magento's db. However, I can't seem to figure out how the "CREATE FUNCTION" call should be set up for Magento to execute it properly.
The SQL I am using is:
DROP FUNCTION IF EXISTS {$this->getTable('fn_Get_HardinessZone')};
CREATE FUNCTION {$this->getTable('fn_Get_HardinessZone')}(IN ZipCode varchar()) RETURNS integer AS
DECLARE Result integer;
BEGIN
SELECT MAX(Zone) into Result
FROM AMI_zones
WHERE (Hfzip <= LEFT(ZipCode, 5)) AND (Htzip >= LEFT(ZipCode, 5));
if Result is null or Result < 1 or (Result > 11 and Result <> 99) Then
/*if the left most character is alpha, then set the zone to 98 for Canada*/
if Left(zipCode, 1) >= 'A' and LEFT(zipcode,1) <= 'Z' THEN
set result = 98;
else
set Result = 99;
End if;
END if;
RETURN Result;
END;
But this always generates the following error:
SQLSTATE[42000]: Syntax error or access violation: 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 'IN ZipCode varchar()) RETURNS'
So what is the proper way to format a SQL call to be run in a module's install/update script to insert a function or stored procedure into Maganeto's database?
The problem is with your SQL statement:
You have an error in your SQL syntax; check the manual ...
for the right syntax to use near
'IN ZipCode varchar()) RETURNS'
I would recommend running the SQL through PhpMyAdmin or on the command line until you get it right, then run it through Magento. This man page describes the syntax of CREATE FUNCTION: http://dev.mysql.com/doc/refman/5.0/en/create-procedure.html. When testing stored procedures /functions in the mysql client (or PhpMyAdmin) be sure to change the delimiter so that the semicolons in your function body are interpreted correctly.
The below SQL worked for me. The things I changed from your original statement are:
IN is not allowed in function declarations (IN ZipCode varchar())
I was required to explicitly state length of the varchar
The DECLARE belongs inside the function
I am guessing that your function is DETERMINISTIC, meaning it will always produce the same results for the same input parameters. If this is not the case, remove DETERMINISTIC from the RETURNS line
Give this a shot:
DROP FUNCTION IF EXISTS {$this->getTable('fn_Get_HardinessZone')};
CREATE FUNCTION {$this->getTable('fn_Get_HardinessZone')} (ZipCode VARCHAR(15))
RETURNS INTEGER DETERMINISTIC
BEGIN
DECLARE result INTEGER;
SELECT MAX(Zone) INTO result
FROM AMI_zones
WHERE (Hfzip <= LEFT(ZipCode, 5)) AND (Htzip >= LEFT(ZipCode, 5));
IF result IS NULL OR result < 1 OR (result > 11 AND result <> 99) THEN
/* if the left most character is alpha, then set the zone to 98 for Canada */
IF LEFT(ZipCode, 1) >= 'A' AND LEFT(ZipCode, 1) <= 'Z' THEN
SET result = 98;
ELSE
SET result = 99;
END IF;
END IF;
RETURN result;
END;