set new value depending on another table value trigger - mysql

What I am trying is to set a new value depending on the value from another table. This is a BEFORE UPDATE trigger. I need to set a new.amount in "webs" table depending on the value of percent column from table "webTransactions". If percent = 30.00 then new amount must change from whatever to 0.00. What I tried so far but is giving me error:
if new.type=9 and new.referenceId=0 then set new.amount=0.00 where (SELECT * FROM webs s JOIN webTransactions r ON r.webId = s.id WHERE s.percent = 30.00);
Anyone can help to make this trigger run?
Thank you

you can try something like this
UPDATE websTransactions
SET amount= CASE
WHEN type=9 AND referenceId=0 THEN 0.00
ELSE amount
END
WHERE key IN
(SELECT key FROM webs s JOIN webTransactions r ON r.webId = s.id
WHERE s.percent = 30.00)
replace key with the primary key of websTransactions

You might want to to use some more efficient code, triggers are a sort of stored routines so program them that way. Also, it's not neccesary to join the table you're updating in a subquery.
DELIMITER $$
CREATE TRIGGER amount_check BEFORE UPDATE ON webs
FOR EACH ROW
BEGIN
IF NEW.type=9 and NEW.referenceId=0 THEN
SET #percent := (SELECT percent
FROM webTransactions
WHERE webId = OLD.id);
IF #percent = 33.00 THEN
NEW.amount = 0
END IF;
END IF;
END$$
DELIMITER ;

Related

Problem with comparison within a trigger statement using a variable gotten from query

I am trying to use an attribute from a 2nd table in the trigger of the 1st. To do this I am trying to load that value into a variable and then use it as a comparison.
However whenever I try and test the process the comparison answers false.
DELIMITER $$
create trigger evolve_persona before update on phantom_thieves
for each row begin
set #t := (select tier from persona where pname = old.persona);
if((new.persona != old.persona) and (select cast(#t as unsigned) = '1')) then
set
new.st = old.st+10, new.ma = old.ma+10, new.en= old.en+10, new.ag= old.ag+10,
new.lu= old.lu+20;
end if;
end$$
DELIMITER ;
I can see nothing wrong with your trigger but, this is somewhat more complicated as be written in a comment.
Make please following
SET #t = -1;
SELECT #t; -- returns -1
update phantom_thieves SET .....
SELECT #t; -should display at sometime 1
This seems to be the only problem that tier don't has the response 1 and with above, you can see what you get.

How to use Case-When and Update in Trigger?(Error in my code)

I tried to create below Trigger but I have an Error.
Can I Use Update or use 'case when' in trigger?
Please help me to fix my issue here.
Code Explanation:
I want to update my existing row after insert or update.
Do not change the 'FUSDate1' or 'FUSDate2' If I didn't add anything to the 'FUSDate1' or 'FUSDate2'
Update the FUSDate to the New One or Inserted one If I Updated or inserted data to FUSDate
Code:
delimiter //
create trigger SafetyCertificationTRG
after insert on SafetyCertification
for each row
begin
case when (FUSDate1='' or FUZDate1 is NULL) then (FUZDate1=OLD.FUSDate1) else (update SafetyCertification set FUZDate1=NEW.FUSDate1) end;
case when (FUSDate2='' or FUZDate2 is NULL) then (FUZDate2=NEW.FUSDate2) else (update SafetyCertification set FUZDate2=NEW.FUSDate2) end;
end //
delimiter ;
Edit: I am going to add some information here to make the question more clear.
I have one column as FUS that can be get these 3 values only:('FUS1', 'FUS2' and 'FUS3')
I have 3 other columns: FUSDate1, FUSDate2, FUSDate3.
I want to save the Current Date to The FUSDate1 Or FUSDate2 Or FUSDate3 based on the user User Selection of FUS. (They are in same Table)
I used the provided answer and change it to this but I cannot do the above.
Code: This code is just for FUS1 and FUSDate1
delimiter //
CREATE TRIGGER SafetyCertification_bu
BEFORE UPDATE ON SafetyCertification
FOR EACH ROW
BEGIN
-- detect a change made to a value in col
IF OLD.FUS <=> NEW.FUS THEN
-- value of col is not changed, so do nothing
DO 0;
ELSE
-- we detected a new value was assigned to col
IF OLD.FUS ='%FUS1%' THEN
-- we can override the new value, keep it the same
SET NEW.FUSDate1 = CURDATE();
END IF;
END IF;
END //
delimiter ;
Another code that I expected to do my work but still have problem, Does not update Like above Code:
delimiter //
CREATE TRIGGER SafetyCertification_bu
BEFORE INSERT ON SafetyCertification
FOR EACH ROW
BEGIN
IF NEW.FUS='%FUS1%' THEN
SET new.FUSDate1=MD5(CURDATE());
END IF;
END //
delimiter ;
Update 3:
The Third code that provided in answer does not add anything to the FUSdate1 and 2 and 3 when i update or insert any data.
Code
DELIMITER $$
CREATE TRIGGER SafetyCertification_bu
BEFORE UPDATE ON SafetyCertification
FOR EACH ROW
BEGIN
-- set one of the `fusdateN` columns to current date
-- which column to set depends on the value assigned to `fus`
IF NEW.fus = 'FUS1' THEN
SET NEW.fusdate1 = DATE(NOW());
ELSEIF NEW.fus = 'FUS2' THEN
SET NEW.fusdate2 = DATE(NOW());
ELSEIF NEW.fus = 'FUS3' THEN
SET NEW.fusdate3 = DATE(NOW());
END IF;
END$$
DELIMITER ;
A couple of notes:
A trigger cannot issue an UPDATE against the table that fired the trigger, this is prohibited.
The unqualified references (e.g. FUSDate1 and FUZDate1) are not valid. Those references don't resolve to anything.
The reference to OLD.FUSDate1 is invalid in the context of an AFTER INSERT trigger. In an UPDATE trigger, the OLD.col refers to the value of col before the update.
The expression (FUZDate1=OLD.FUSDate1) is not an assignment, it's a comparison that's going to return 0, 1 or NULL.
If we want to trigger on an UPDATE and an INSERT, that will require two separate triggers.
If we want to modify the contents of the current row, we can use BEFORE trigger instead of AFTER.
I want to update my existing row after insert or update.
It would be much easier to apply changes before the row is inserted or updated. We can assign a value to a column col by referencing NEW.col in an assignment in a BEFORE INSERT or BEFORE UPDATE trigger. For example:
SET NEW.col = expr;
Do not change the FUSDate1 or FUSDate2 If I didn't add anything to the FUSDate1 or FUSDate2
This seems pretty straightforward. Just don't make any assignments to NEW.FUSDate1 or NEW.FUSDate2.
Update the FUSDate to the New One or Inserted one If I Updated or inserted data to FUSDate
The example proposed trigger contains references to FUZDate1 or FUZDate2, but there's no mention of these columns in the specification. The specification is confusing.
An UPDATE statement will assign a value to a column, no need for a trigger to do that. An INSERT statement can assign a value to a column, again, no need for a trigger for that.
The specification is not clear. Providing example starting state (rows in the table), and example INSERT or UPDATE statements, and the desired state after the statement is executed would go a long ways towards clarifying the requirements.
A demonstration of a BEFORE UPDATE trigger that prevents a new value being assigned to a particular column:
DELIMITER $$
CREATE TRIGGER SafetyCertification_bu
BEFORE UPDATE ON SafetyCertification
FOR EACH ROW
BEGIN
-- detect a change made to a value in col
IF OLD.col <=> NEW.col THEN
-- value of col is not changed, so do nothing
DO 0;
ELSE
-- we detected a new value was assigned to col
IF OLD.col IS NOT NULL THEN
-- we can override the new value, keep it the same
SET NEW.col = OLD.col;
END IF;
END IF;
END$$
DELIMITER ;
For what this example trigger achieves, we don't necessarily need that many IF conditions; those are included as a demonstrate some of the checks we can perform, how we can make references to the existing value of col and the new value assigned to col.
FOLLOWUP
Based on the update information in the question, here's an example of a BEFORE UPDATE trigger that satisfies the specification.
This is for the UPDATE action. To get this same behavior with an INSERT statement, this trigger definition needs to be repeated, with BEFORE INSERT in place of BEFORE UPDATE.
(I would use the name _bu for the before update trigger, and _bi for before insert trigger.)
DELIMITER $$
CREATE TRIGGER SafetyCertification_bu
BEFORE UPDATE ON SafetyCertification
FOR EACH ROW
BEGIN
-- set one of the `fusdateN` columns to current date
-- which column to set depends on the value assigned to `fus`
IF NEW.fus = 'FUS1' THEN
SET NEW.fusdate1 = DATE(NOW());
ELSEIF NEW.fus = 'FUS2' THEN
SET NEW.fusdate2 = DATE(NOW());
ELSEIF NEW.fus = 'FUS3' THEN
SET NEW.fusdate3 = DATE(NOW());
END IF;
END$$
DELIMITER ;
second followup
To answer the question about using CASE WHEN statement in the context of a MySQL stored program...
We could implement the example trigger (directly above in this answer) replacing the IF-THEM with either of the two forms of the CASE statement.
either
CASE
WHEN NEW.fus = 'FUS1' THEN
SET NEW.fusdate1 = DATE(NOW());
WHEN NEW.fus = 'FUS2' THEN
SET NEW.fusdate2 = DATE(NOW());
WHEN NEW.fus = 'FUS3' THEN
SET NEW.fusdate3 = DATE(NOW());
END CASE;
-or-
CASE NEW.fus
WHEN 'FUS1' THEN
SET NEW.fusdate1 = DATE(NOW());
WHEN 'FUS2' THEN
SET NEW.fusdate2 = DATE(NOW());
WHEN 'FUS3' THEN
SET NEW.fusdate3 = DATE(NOW());
END CASE;
note
The CASE statement is available in MySQL stored programs; outside of a stored program, it is not a valid SQL statement.
Also, we should not confuse this CASE statement with the CASE expression. The CASE expression is valid in the context of a SQL statement, such as a SELECT or UPDATE statement.
DEMONSTRATION
"I examined the Trigger, But unfortunately does not save anything in fusDates."
#Christiano: here is a simple demonstration
create table
CREATE TABLE `safety_certification`
( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
, fus VARCHAR(5)
, fusdate1 DATE
, fusdate2 DATE
, fusdate3 DATE
) ENGINE=INNODB
;
populate table with demonstration rows
INSERT INTO `safety_certification` (id, fus, fusdate1, fusdate2, fusdate3) VALUES
( 1, '', NULL, NULL, NULL)
,( 2, '', NULL, NULL, NULL)
,( 3, '', NULL, NULL, NULL)
,( 4, '', NULL, NULL, NULL)
,( 5, '', NULL, NULL, NULL)
;
create trigger
DELIMITER $$
CREATE TRIGGER `safety_certification_bu`
BEFORE UPDATE ON `safety_certification`
FOR EACH ROW
BEGIN
-- set one of the `fusdateN` columns to current date
-- which column to set depends on the value assigned to `fus`
IF NEW.fus = 'FUS1' THEN
SET NEW.fusdate1 = DATE(NOW());
ELSEIF NEW.fus = 'FUS2' THEN
SET NEW.fusdate2 = DATE(NOW());
ELSEIF NEW.fus = 'FUS3' THEN
SET NEW.fusdate3 = DATE(NOW());
END IF;
END$$
DELIMITER ;
updates will exercise BEFORE UPDATE trigger we just defined
UPDATE `safety_certification` sc SET sc.fus = 'FUS1' WHERE sc.id = 1 ;
UPDATE `safety_certification` sc SET sc.fus = 'FUS2' WHERE sc.id = 2 ;
UPDATE `safety_certification` sc SET sc.fus = 'FUS3' WHERE sc.id = 3 ;
UPDATE `safety_certification` sc SET sc.fus = 'FUS4' WHERE sc.id = 4 ;
display contents of table
SELECT * FROM `safety_certification`;
returns:
id fus fusdate1 fusdate2 fusdate3
------ ------ ---------- ---------- ------------
1 FUS1 2018-05-04 (NULL) (NULL)
2 FUS2 (NULL) 2018-05-04 (NULL)
3 FUS3 (NULL) (NULL) 2018-05-04
4 FUS4 (NULL) (NULL) (NULL)
5 (NULL) (NULL) (NULL)
seems like the trigger is populating the columns fusdate1, fusdate2 and fusdate3 per the specification, when some particular values are assigned to fus
I had a same problem and I used two trigger,
First trigger send data to the other table, so now you can create another trigger to send this data to the first table. I think it is low performance but it is the only way that I reached to it. I hope others have another solution for u.

How to trigger the procedure for the sql database in system files

I have a table that holds a bunch of values for an order, I can do basic calculations on it until I get to a percentage. Right now I have my query as follows
declare #MyNumber decimal
set #MyNumber = (select SalesTax from [OrderHeader] where OrderHeaderID = 20)
select
sum(o.MaterialPrice) as "MatPrice",
sum(o.LaborPrice) as "LaborPrice",
sum(o.MaterialCost) as "MaterialCost",
sum(isnull(o.MaterialPrice,0)) - sum(isnull(o.MaterialCost,0)) - sum(isnull(o.LaborPrice,0)) * #MyNumber as "RESULT"
from [OrderDetail] o
inner join [OrderHeader] oh on oh.OrderHeaderID = o.OrderHeaderID
where o.OrderHeaderID = 20
PLEASE CHANGE AT LEAST NAZOV
DELIMITER $$
CREATE TRIGGER `nazov` BEFORE UPDATE
ON test
FOR EACH ROW BEGIN
SET NEW.OLD_TEXT=OLD.TEXT;
END $$
DELIMITER;

MySQL 1422, explicit or implicit commit is not allowed in trigger

I understand that I cannot do a transaction inside a trigger, but I CAN inside a procedure. And I should be able to call a procedure from a trigger. Which is exactly what I'm doing.
TABLE A has an "after update trigger".
I only want to call the procedure if one of two columns has been changed.
TABLE A TRIGGER:
IF (
NEW.colA != OLD.colA
OR
NEW.colB != OLD.colB
) THEN
call setBonuses( NEW.colA, NEW.colB );
END IF
The setBonuses SP effects TABLE B by doing some calculations using TABLE_A.colA,TABLE_A.colB (I don't think it's relevant, but TABLE B does have an "after update trigger", but it has a conditional to only do its update if fields NOT effected by the below procedure are changed, so it does 'nothing' when the bonus field is updated.)
THE STORED PROCEDURE:
begin
IF A > B THEN
SET n = A;
...
ELSEIF A < B THEN
SET n = B;
...
END IF;
start transaction;
-- Bonuses
UPDATE TABLE_B
SET bonus = 0
WHERE... ;
UPDATE TABLE_B
SET bonus = bonus + n
WHERE...;
UPDATE TABLE_B
SET bonus = bonus + n
WHERE...;
UPDATE TABLE_B
SET bonus = bonus + n
WHERE...;
UPDATE TABLE_B
SET bonus = bonus + n
WHERE...;
UPDATE TABLE_B
SET bonus = bonus + n
WHERE...;
commit;
end
The SP works fine if called directly by the application, however, I don't want to have to explicitly call it as a chain in some event, I really just need it to do its calcs and update TABLE B - whenever someone changed TABLE A (colA or colB).
Any reason why this isn't possible.

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);