MYSQL: why is the following update trigger not working? - mysql

CREATE TRIGGER `add_history` AFTER UPDATE ON `meters`
FOR EACH ROW
CASE inserted.id
WHEN 2 THEN
INSERT INTO waterlog SET deciliter = 5;
WHEN 3 THEN
INSERT INTO eleklog SET kwh = 1;
END CASE
Depending on the row that is updated ( a record with id 2 or 3),i want to run a different query.
meters table looks like
id meter value
2 water 121
3 elek 344
value is regularly updated and need to trigger the creating of a log entry in another table.

Try this:
CREATE TRIGGER `add_history` AFTER UPDATE ON `meters`
FOR EACH ROW
IF (NEW.id = 2) THEN
INSERT INTO waterlog SET deciliter = 5;
ELSEIF (NEW.id = 3) THEN
INSERT INTO eleklog SET kwh = 1;
ENDIF

Related

How to add unique random values to the column in mysql

I want to add 1000 unique random values to the column AgentID to the table agents.
I have used Upsert to ignore the duplicate values. What I have done so far:
DROP PROCEDURE IF EXISTS Generate_random;
DELIMITER $$
CREATE PROCEDURE Generate_random()
BEGIN
Drop table if exists ai_training.`Agents`;
CREATE TABLE ai_training.`Agents`(AgentID int PRIMARY KEY);
SET #first = 1;
SET #last = 1000;
WHILE(#first <= #last) Do
INSERT INTO ai_training.`Agents` VALUES(
FLOOR(RAND()*(2900000-2800000+1)+2800000)
)
ON DUPLICATE KEY UPDATE AgentID = FLOOR(RAND()*(2900000-2800000+1)+2800000);
SET #first = #first + 1;
END WHILE;
END$$
DELIMITER ;
CALL Generate_random();
Select * from ai_training.`Agents`;
The problem is I need 1000 unique agentid's and this code is generating 1000 - the repeated ones. So, if it finds 6 repeated ids it returns 994 rows and not 1000.
Is there any way I can achieve this?
Can't change the random ID generation part.
You could use information function ROW_COUNT() to check whether a row was actually inserted or not, and increment the counter accordingly.
The documentation states:
With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if the row is inserted as a new row, 2 if an existing row is updated, and 0 if an existing row is set to its current values.
So:
WHILE(#first <= #last) DO
INSERT INTO ai_training.`Agents`
VALUES(FLOOR(RAND()*(2900000-2800000+1)+2800000))
ON DUPLICATE KEY UPDATE AgentID = AgentID;
IF ROW_COUNT() = 1 THEN
SET #first = #first + 1;
END IF;
END WHILE;
Note that I changed the action on duplicate key to a dummy update rather than re-assigning a new random value; this makes things a little less expensive when a collision happens.
CREATE PROCEDURE Generate_random()
BEGIN
Drop table if exists ai_training.`Agents`;
CREATE TABLE ai_training.`Agents`(AgentID int PRIMARY KEY);
SET #last = 1000;
WHILE (SELECT COUNT(*) FROM ai_training.`Agents`) < #last DO
INSERT IGNORE INTO ai_training.`Agents`
VALUES
(FLOOR(RAND()*(2900000-2800000+1)+2800000));
END WHILE;
END

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.

Trigger syntax wrong

I'm trying to create a trigger to give "SumBeforeTaxes(from 'order')" a value.
The "SumBeforeTaxes" is itemQuantity(from 'order_item') x price ('from itemsinstock').
So if one has ordered 3 items at 10 USD each, the "SumBeforeTaxes" would be 3 x 10 (30 in total). Likewise, if one has ordered 3 items at 10 USD each AND 2 items at 15 each, the "SumBeforeTaxes" should be 3x10 + 2x15 (60 in total).
Here's what I've tried so far - but I keep getting syntax errors. I'm also not sure my triggers (despite the syntax errors) are correct.
1st attempt:
CREATE DEFINER = CURRENT_USER TRIGGER `orderdb`.`order_AFTER_INSERT`
AFTER INSERT ON `order_item` FOR EACH ROW
BEGIN
SET getItemPrice = (SELECT Price FROM itemsinstock);
INSERT orderdb.'order'
SET SumBeforeTax = itemQuantity * getItemPrice;
END
2nd attempt:
CREATE DEFINER = CURRENT_USER TRIGGER `orderdb`.`order_AFTER_INSERT`
AFTER INSERT ON `order_item` FOR EACH ROW
BEGIN
SET getItemPrice = (SELECT Price FROM itemsinstock);
INSERT INTO orderdb.'order' (SumBeforeTax) VALUES (new.itemQuantity * getItemPrice);
END
3rd attempt:
CREATE DEFINER = CURRENT_USER TRIGGER `orderdb`.`order_AFTER_INSERT`
AFTER INSERT ON `order_item` FOR EACH ROW
BEGIN
declare getItemPrice DOUBLE;
SET getItemPrice = (SELECT Price FROM itemsinstock WHERE ItemID = new.itemID);
INSERT INTO orderdb.'order'(SumBeforeTax) VALUES (itemQuantity * getItemPrice);
END
Can I get a little help on this one?
order is a reserve word in MySQL and thus you need to escape it like below using backtique for your INSERT statement.
INSERT INTO orderdb.`order`(SumBeforeTax) VALUES (itemQuantity * getItemPrice);
For any syntactical clarification refer Documentation On CREATE TRIGGER Syntax.
You might want to change your code like below in that case using an UPDATE statement rather:
BEGIN
declare getItemPrice DOUBLE;
SELECT Price INTO getItemPrice FROM itemsinstock WHERE ItemID = new.itemID;
UPDATE orderdb.`order` SET SumBeforeTax = new.itemQuantity * getItemPrice
WHERE OrderID = 101;

MySQL trigger to update other table

I have 2 tables:
table 1 = SAMPLE_TABLE
table 2 = RESULT_TABLE (with proposed trigger)
I would like to use a trigger in RESULT table that, when a new record is inserted into into it, will update a field in SAMPLE table called, 'status' = "complete". The field 'status' to be updated in SAMPLE is related to RESULT by:
table 1 = SAMPLE_TABLE ('client_sampleID')
=
table 2 = RESULT_TABLE ('sampleID')
This is the proposed trigger
CREATE DEFINER = `user`#`%` TRIGGER `database`.`RESULT_TABLE_BEFORE_INSERT`
AFTER INSERT ON `RESULT_TABLE` FOR EACH ROW
BEGIN
UPDATE SAMPLE_TABLE
SET status = 'complete'
WHERE SAMPLE_TABLE.client_sampleID = RESULT_TABLE.sampleID;
END
My questions:
is this above trigger OK?
there are 100+ 'client_sampleID' (all same, entered as a batch) per 'sampleID'. Is there a more efficient way of setting the 'status' so that it happens only after encountering the first instance?
You are very close. You just need to use new in the trigger:
CREATE DEFINER = `user`#`%` TRIGGER `database`.`RESULT_TABLE_BEFORE_INSERT`
AFTER INSERT ON `RESULT_TABLE` FOR EACH ROW
BEGIN
UPDATE SAMPLE_TABLE st
SET status = 'complete'
WHERE st.client_sampleID = new.sampleID;
END

mysql triggers have some issue in updating my table

hi
i have created a trigger which i want to update a table field when insertion in another field occurs.but i don,t know how should it know that its updating the same user row who is inserting here is some code and database senerio
--> admin_reg_abr
'id course_limit username
10 0 ahmad '
note: id is primry key
--> abroad_course
'id uni_id username
1 10 ahmad'
note: uni_id is foriegn key or same as id in admin_reg_abr.
i write the following code for trigger:
DROP TRIGGER IF EXISTS
ahmad.AI_course_each//
CREATE TRIGGER ahmad.AI_course_each
AFTER INSERT ON ahmad.abroad_course
FOR EACH ROW BEGIN
UPDATE admin_reg_abr SET
admin_reg_abr.course_limit =
admin_reg_abr.course_limit + 1 WHERE
admin_reg_abr.id = new.id; END //
i want to update the same id how insert in the table but its not working.
Didn't You mean:
DROP TRIGGER IF EXISTS ahmad.AI_course_each//
CREATE TRIGGER ahmad.AI_course_each
AFTER INSERT ON ahmad.abroad_course FOR EACH ROW
BEGIN
UPDATE admin_reg_abr SET
admin_reg_abr.course_limit = admin_reg_abr.course_limit + 1
WHERE admin_reg_abr.id = new.uni_id;
END //
Note that in Your code NEW.id points nowhere in admin_reg_abr table
One more thing. You are talking about firing trigger on UPDATE, so, You would probably need another trigger:
DROP TRIGGER IF EXISTS ahmad.AI_course_each//
CREATE TRIGGER ahmad.AI_course_each
AFTER UPDATE ON ahmad.abroad_course FOR EACH ROW
BEGIN
UPDATE admin_reg_abr SET
admin_reg_abr.course_limit = admin_reg_abr.course_limit + 1
WHERE admin_reg_abr.id = new.uni_id;
END //