mySQL trigger - What is wrong with my syntax? - mysql

I need to write a trigger where if a customerName of an incoming enquiry matches a customer name in a synonymns table then the customerID from that table is used to find the customer in the customer table.
I got a trigger to work which just searched the customer table but not the synonym table first. I was thinking something like: (It's psuedo-esque code)
CREATE TRIGGER `Find Customer` AFTER INSERT ON `enquiry` FOR EACH ROW
BEGIN
INSERT INTO customersmatched (enquiryID, customerID)
SELECT NEW.id, id, customerName, customerID FROM customer, customerSynonyms WHERE
customerSynonyms.customerName = NEW.companyName AND customer.id = customerSynonyms.customerID
HAVING COUNT(id)=1
END;
The error I recieve:
#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' at line 7
But I'm afriad this doesn't work.
Any idea how one would go about this in mySQL? Thanks!
UPDATE
I tried this way too - it didn't work either!
DELIMITER $$
CREATE TRIGGER Find_Customer AFTER INSERT ON enquiry
FOR EACH ROW
BEGIN
IF EXISTS (SELECT customerID FROM customerSynonyms WHERE customerName = NEW.companyName) THEN
IF EXISTS (SELECT id FROM customer WHERE id = #customerID) THEN
INSERT INTO customersMatched (enquiryID, customerID)
HAVING COUNT(id)=1
END IF;
END IF;
END$$
DELIMITER ;
Update 2
It turns out I was WAYYY over complicating things. The customerSynonym table had the customerID stored in a column, which was all I really needed as I could just grab all the data through php with the customerID. The final trigger which works was super simple:
INSERT INTO customersmatched (enquiryID, customerID)
SELECT NEW.id, customerID FROM customersynonyms WHERE
customersynonyms.customerName=NEW.companyName
HAVING COUNT(id)=1
Thanks for all your answers, they're always very much appreciated! :-)

I think you want something like this:
CREATE TRIGGER Find_Customer AFTER INSERT ON enquiry FOR EACH ROW
BEGIN
INSERT INTO customersmatched (enquiryID, customerID)
SELECT NEW.id, customerID FROM customer, customerSynonyms
WHERE customerSynonyms.customerName = NEW.companyName
AND customer.id = customerSynonyms.customerID
HAVING COUNT(id)=1
END;
A few things to note:
I renamed the trigger to Find_Customer. I'm not 100% sure if you can have a space in the trigger name
I removed the single quotes around Find_Customer and enquiry. The single quotes could be read as a string literal by mysql and cause problems. It's better to avoid that if possible.
I changed your select query to only select NEW.id and customerID, since those are the only two things you're inserting. You might have to play with the select a little bit more to get it exactly how you want it.
If this is just part of the trigger, and you have more than just a one-statement trigger, you'll need to set delimiters. Basically, you'd have delimiter | before the trigger definition, and then END| instead of END
Good luck!

Related

mysql double trigger two updates together

After trying to create a new trigger in invoices table to UPDATE `invoices` SET invoices.`owes` = (`owes` - `paid`);
I get an error because I already that another trigger in payments that is updating. (see below)
I'm looking to keep the existing trigger below, but how to modify it to also update owes to (owes - paid) in the invoices table.
CREATE TRIGGER `after_payment_update` AFTER UPDATE
ON `payments`
FOR EACH ROW UPDATE `invoices`
SET invoices.`paid` = (SELECT SUM(payments .`payment`)
FROM payments WHERE payments.`invoice` = invoices.`invoice`)
You can't create a second trigger that "triggers" on the same action as another trigger. Instead you would use a DELIMITER $$ statement like below and fill your trigger with all the relevant code you want executed.
DELIMITER $$
CREATE TRIGGER after_update_payments
AFTER UPDATE ON payments
FOR EACH ROW BEGIN
UPDATE invoices
SET NEW.paid = (SELECT SUM(payment) FROM payments WHERE invoice = NEW.invoice),
NEW.owes = (owes -(SELECT SUM(payment) FROM payments WHERE invoice = NEW.invoice));
END $$
DELIMITER ;
You don't actually need a DELIMITER in the trigger above, so I will show you an example where you would need to use it:
DELIMITER $$
CREATE TRIGGER after_update_payments
AFTER UPDATE ON payments
FOR EACH ROW BEGIN
IF (some condition here) THEN
UPDATE invoices
SET NEW.paid = (SELECT SUM(payment) FROM payments WHERE invoice = NEW.invoice),
NEW.owes = (owes -(SELECT SUM(payment) FROM payments WHERE invoice = NEW.invoice));
END IF;
END $$
DELIMITER ;
As a general rule, if you need to execute multiple statements that need a ; at the end of them, you need to use a DELIMITER. If this still doesn't make sense, a great explanation for delimiters can be found here.
Now, on a side-note, I don't think this approach is the most optimal one. What I would do in your situation is create a view that combines these tables. For example:
CREATE
ALGORITHM = UNDEFINED
DEFINER = `root`#`localhost`
SQL SECURITY DEFINER
VIEW invoice_payments_view AS (
SELECT
t1.*,
SUM(t2.payment) as amount_paid,
SUM(t2.owes - SUM(t2.payment)) as amount_owed
FROM invoices t1
JOIN payments t2 ON (t1.invoice=t2.invoice)
GROUP BY t1.invoice
)
Then to access the amount_paid and amount_owed columns, you would simply query the following:
SELECT invoice, amount_paid, amount_owed FROM invoice_payments_view
WHERE invoice=1;
Note that I am by no means an expert on this topic, and I am only showing you how I would approach this situation. Also, I didn't test any of this code, so you might need to modify it slightly. If you have any issues let me know and I can update.

AFTER INSERT Trigger to insert data into a different table after inserting it into initial table

Hello and thanks in advance for any help given!
I have created a very simple database for an electronics online shop.
Among the other tables I have a tbl_orders for orders being placed manually (user inserts the product_id, number of units, payment_details_id and so on manually) and I want to make an AFTER INSERT trigger on tbl_orders that would send the order_id (which is tbl_order's PK) to a table called purchase_history.
The table purchase_history also has a purchase_date column. It's PK is purchase_id, with order_id as a FK.
I am unfamiliar with triggers but I've tried all sorts of simple queries inside a trigger with no luck, though the errors I was getting were getting "better" if one could call it that.
The last try I had was this:
CREATE DEFINER = CURRENT_USER TRIGGER `onlineshop`.`tbl_orders_AFTER_INSERT` AFTER INSERT ON `tbl_orders` FOR EACH ROW
BEGIN
INSERT INTO purchase_history (order_id)
VALUES (NEW.order_id);
INSERT INTO purchase_history ( purchase_date )
VALUES (purchase_date = NOW());
END
I am using MYSQL Workbench, which is great but also, sometimes, slightly buggy or confusing.
CREATE TRIGGER `tbl_orders_AFTER_INSERT` AFTER INSERT ON `tbl_orders`
FOR EACH ROW BEGIN
INSERT INTO purchase_history (order_id, purchase_date) VALUES (NEW.order_id, NOW());
END;
This way your insert would make more sense, as you would want both of the data in the same row in the history, I'd guess.
If the DEFINER-line is needed:
CREATE DEFINER = CURRENT_USER
TRIGGER stuff.`tbl_orders_AFTER_INSERT` AFTER INSERT ON `tbl_orders`
FOR EACH ROW
INSERT INTO purchase_history (order_id, purchase_date) VALUES (NEW.order_id, NOW());
I tried some things, mysql seems not to like begin, end and DEFINER = ... at the same time when creating triggers. Though BEGIN and END are not needed with triggers so there is no problem in removing them from your statement.
You can use the below syntax to execute it. First we need to change delimiter if there is multiple statament.
DELIMITER #
create trigger SportsTriggerInsert after insert on sports
for each row begin
insert into settings(sports_id, auto_add_on_matches)
values (new.id, 0);
end;#
DELIMITER ;

create trigger on update to insert old values into other table in MYSQL

I have two tables. The first is my person table which has id, name, creation_date as values, I have a old_person table (id, name, modified_date) which I want to populate the value of person before it actually changes. How would I go about that? I have tried triggers but failed.
I tried as follows
create trigger Person_Trigger Update on person
before update
as
insert into old_person(id, name, modified)
select id, new.name, getdate()
from person
It's giving me syntax errors...Not many Trigger references out there either, a little push would be greatly appreciated!
Have a look at the following example
SQL Fiddle DEMO
IO hade a bit of trouble myself, but from How to Create Triggers in MySQL there was a line that made me think
The first MySQL command we’ll issue is a little unusual:
DELIMITER $$
Our trigger body requires a number of SQL commands separated by a
semi-colon (;). To create the full trigger code we must change
delimiter to something else — such as $$.
Finally, we set the delimiter back to a semi-colon:
DELIMITER ;
So in the SQL Fiddle I changed the query terminator to GO and that seemed top work.
CREATE TABLE person
(
id INT,
name varchar(20)
)
GO
CREATE TABLE old_person
(
id INT,
name varchar(20),
modified DATETIME
)
GO
CREATE TRIGGER Person_Trigger before update on person
FOR EACH ROW BEGIN
INSERT INTO old_person(id, name, modified)
VALUES (OLD.id, OLD.name, NOW());
END
GO
INSERT INTO person VALUES (1,'TADA')
GO
UPDATE person SET name = 'FOO'
GO
Try this:
DELIMITER \\
CREATE TRIGGER `Person_Trigger`
BEFORE UPDATE ON `Person`
FOR EACH ROW
BEGIN
DECLARE date_modified datetime;
SET date_modified = NOW();
INSERT INTO old_person(id, name, modified)
VALUES (OLD.id, OLD.name, date_modified);
END\\
This syntax works for me on my own projects. You may also need to declare delimiters before you begin the trigger. Also if you want to use the NEW keyword it should be AFTER update. Switch to the OLD keyword if you are going to keep using BEFORE update on your trigger.

MySQL write a trigger to prevent from buying too much

I have a table warehouse where I have information about articles in my store (article id as foreign key and quantity). Then, I have another table, shoppinglist where I have a clients id, article id and quantity. Lets say, that client wants to buy 3 articles but theres only one article available. How to write a trigger which help me to prevent from buying too much?
I tried this:
DELIMITER $$ CREATE TRIGGER check BEFORE INSERT ON shoppinglist FOR EACH ROW BEGIN IF warehouse.quantity < shoppinglist.quantity THEN CALL fail('You cant buy that much'); END IF; END $$ DELIMITER;
but this seems not to work. I mean, when I do:
INSERT INTO shoppinlist (clients_id, article_id, quantity) VALUES (1, 2, 100);
having only 2 articles with id = 2 on warehouse its ok, its possible. What did I do wrong?
What specific article would warehouse.quantity or shoppingList.quantity refer to in your code?
Also, check is a reserved keyword.
Try this:
DELIMITER $$
CREATE TRIGGER qtyCheck BEFORE INSERT ON shoppinglist
FOR EACH ROW
BEGIN
SET #qty = (SELECT quantity FROM warehouse WHERE article_id = NEW.article_id);
IF #qty < NEW.quantity THEN
CALL fail('You cant buy that much');
END IF;
END $$
DELIMITER ;
Note that I renamed the trigger, I'm guessing the name of the article_id column on the warehouse table, I used the NEW variable instead of shoppingList within the body of the trigger, and you need a space before the semicolon in DELIMITER ;, though this might've been a typo when posting.
Finally, you may get the following error if the fail function isn't defined. It doesn't exist on my system...
ERROR 1305: PROCEDURE testing.fail does not exist

MySQL table .new supposedly does not exist, when referencing in trigger

I have the following three (InnoDB-) tables in a MySQL database:
Entity (DLID)
Category (CatID, CatName)
hasCategory (DLID, CatID)
Now, upon insertion into the table hasCategory I would like to make sure, that each Entity is associated with at least one Category. Thus, I wrote the following trigger:
delimiter |
create trigger Max before insert on hasCategory for each row begin
if (exists (select distinct DLID from Entity where not exists (select distinct new.DLID from new))) then
signal sqlstate '45000'
set message_text = 'Min of 1 category per entity required';
end if;
end|
delimiter ;
Now, when I execute the following query: insert into hasCategory values (1, 1); I get the error error code 1146: table mydb.new does not exist. I have created some other triggers similar to this one, also referring to the new-table, where it worked perfectly well. Yet, I don't get it, what causes the error in this particular trigger.
Is it possible that the select statement causes some trouble? I've read that only select into statements are valid in procedures, but I don't know if this has got anything to do with this.
Thanks for your help!
select distinct new.DLID from new
there is no table new in your DB just as the error states. You can use NEW for the record that will be inserted in your trigger but you cannot use it as a table name and select from it.
try
if (select 1 from Entity where DLID = new.DLID) = 1 then