I have learned the triggers in Oracle SQL, and not that well versed in MySQL. I was trying to convert a trigger command from Oracle to MySQL. First of all, I am not able to find the when statement, I found the if else instead. This is what I wrote:
create trigger overdraft
after update on account
for each row
begin
if account.balance < 0 then
insert into borrower(select customer_name, account_number from depositor where new.account_number=depositor.account_number);
insert into loan(select new.account_number, new.branch_name, new.balance);
update account set balance = 0 where account.account_number = new.account_number;
end if;
end;
But I am getting three syntax errors, first at end of first insert statement at the left parenthesis saying, "Statement is incomplete, expecting : ','". Other two are on each of the ends saying "end is not valid at this position: Expecting BEGIN, EOF,....". What is wrong with me code? I am having hard time figuring out.
There are several things. delimiter probably being one of them:
delimiter $$
create trigger overdraft before update on account
for each row
begin
if new.balance < 0 then
insert into borrower (customer_name, account_number) -- column list here
select d.customer_name, d.account_number
from depositor d
where new.account_number = d.account_number;
insert into loan (account_number, branch_name, balance) -- column list here
select new.account_number, new.branch_name, new.balance;
set new.balance = 0;
end if;
end;$$
delimiter ;
Notes:
delimiter is needed so the definition of the trigger does not end at the first semi-colon.
The reference in the initial if (account.balance) is not understood, because account is not defined.
You want to update the balance in the row with the trigger. Hence, you want a before update trigger, not an after update trigger.
When inserting rows into a table, you should always list the columns being inserted. I have speculated on the column names above.
Simply use Delimiter like this.
I thought that you had tested all the insert.
Inser ino mus be like the example wthat i written,but the columnnames could differ.
As i described you can't use the same table in your trigger that fired the trigger. so use the set paramter to change the balance to 0
DELIMItER //
create trigger overdraft
after update on account
for each row
begin
if account.balance < 0 then
insert into borrower (customer_name, account_number) select customer_name, account_number from depositor
where new.account_number=depositor.account_number;
insert into loan (account_number, branch_name, balance) select new.account_number, new.branch_name, new.balance;
set new.balance = 0;
end if;
end;
DELIMItER ;
Related
I need to create a trigger to update the data on another table when an update statement is made on the present table.
I have two tables, a book table, and a borrowed-book table. On the book table, I have an available copies column and on the borrowed-book table, I have a copy and book-status column.
So presently the trigger I am creating is meant to update the book table available-copies column by adding the values with the data on copies column after an update on the borrowed-book, if the book-status on the update is equal to 'returned'.
what do I do:
BEGIN
DEFAULT #status TEXT
SELECT new.status as status from borrowed_book where borrowed_ID=new.borrowed_ID
if status=="returned"
UPDATE books b
set
b.availableCopies=b.availableCopies + New.copies where b.book_ID=new.book_ID
END
You don't need a query to get the status, just use new.status in the IF statement.
DELIMITER $$
CREATE TRIGGER book_returned AFTER UPDATE ON borrowed_books
FOR EACH ROW
IF new.status = 'returned'
THEN
UPDATE books b
SET b.availableCopies=b.availableCopies + New.copies
WHERE b.book_ID=new.book_ID;
END IF;
$$
DELIMITER ;
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.
I've the following trigger which is really bugging me.
I want to do an UPDATE inside the trigger, but MySQL doesn't allow it, since the statement "triggering" the trigger refer to the participants table.
What can I do in order to make it work? I've considered stored procedures, but they are also forbidden in this case.
The logic is: I've a table with participants in a meeting. The invariant that people from the 'tap' group should always accept the invitation if someone from the 'vip' group is attending. In this case, if a 'vip' is attending the meeting I must UPDATE all 'tap' attendances, but how is this possible???
DELIMITER $$
CREATE TRIGGER tap_meet_vip
BEFORE INSERT ON participants
FOR EACH ROW BEGIN
IF (NEW.pid IN (SELECT userid FROM people WHERE `group` = 'vip')) THEN # new participant is a member of the vip group
UPDATE participants SET `status` = 'a' WHERE pid IN (SELECT userid FROM people WHERE `group` = 'tap') AND meetid = NEW.meetid ; # update status to `accept` of all tap group participants
ELSEIF (NEW.pid IN (SELECT userid FROM people WHERE `group` = 'tap') AND EXISTS (SELECT * FROM participants INNER JOIN people ON pid = userid WHERE `group` = 'vip')) THEN # new participant is a member of the tap group and meeting has vip participant
SET NEW.`status` = 'a';
END IF;
END;$$
The above is written using MySQL and the version is 5.6.
It seems that you can't do all this in a trigger. Trigger is already locked the table so update statement can't get the lock. According to the mysql:
Within a stored function or trigger, it is not permitted to modify a
table that is already being used (for reading or writing) by the
statement that invoked the function or trigger
So you can create a stored procedure, that inserts into/Updates the target table, then updates the other row(s), all in a transaction. With a stored proc you'll manually commit the changes (insert and update).
DROP PROCEDURE IF EXIST marks;
DELIMITER $$
CREATE PROCEDURE marks(IN marks INT)
BEGIN
INSERT INTO first VALUES(marks);
END $$
DELIMITER ;
START TRANSACTION;
INSERT INTO first VALUES (16);
CALL marks(18);
COMMIT;
I'm trying to create a trigger, however I keep getting back a syntax error.
Here's the statement:
DELIMITER $$
CREATE TRIGGER `swtalentbank`.`after_candidate_insert`
AFTER INSERT ON `Candidates` FOR EACH ROW
BEGIN
INSERT INTO useradmin (username, talent)
VALUES (NEW.email, 1);
UPDATE `Candidates` SET UserID = useradmin.userid where useradmin.username = NEW.email;
END
DELIMITER ;
I have a registration form on my site. When a person registers it populates the Candidates table with their profile information.
In the Candidates table, there are various fields, two of them being 'email' and 'UserID'.
UserID is also the PK in 'useradmin', so I'm linking the two up.
So when a user registers, I need to insert a record into 'useradmin' with the email address that's just been used to register, and then update the 'Candidates' table, with UserID that's just been created in 'useradmin'.
I hope this makes sense?
NB. I am changing the delimiter before running the statement.
Besides properly using DELIMITER when creating a trigger you have at least two fundamental issues with your current code:
In MySQL you can't use issue a DML statement (in your case UPDATE) against a table (candidates) on which you defined a trigger (also candidates). Your only option is to use BEFORE trigger and set a value of userid column of a row being inserted to a proper value.
You can't arbitrarily reference a column (useradmin.userid) of a table out of the context like you did in your UPDATE. You didn't joined useradmin table or used it in a subquery.
That being said and assuming that userid in useradmin table is an auto_increment column your trigger might look like this
DELIMITER $$
CREATE TRIGGER after_candidate_insert
BEFORE INSERT ON candidates
FOR EACH ROW
BEGIN
INSERT INTO useradmin (`username`, `talent`) VALUES (NEW.email, 1);
SET NEW.userid = LAST_INSERT_ID();
END$$
DELIMITER ;
Here is SQLFiddle demo
You should use semicolon after end your insert query.
You can use INSERT ... ON DUPLICATE KEY UPDATE syntax for your purpose
try out this...
DELIMITER $$
CREATE TRIGGER `swtalentbank`.`after_candidate_insert`
AFTER INSERT ON `Candidates` FOR EACH ROW
BEGIN
INSERT INTO useradmin (username, talent)
VALUES (NEW.email, 1);
UPDATE `Candidates` SET UserID = useradmin.userid where useradmin.username = NEW.email;
END $$
DELIMITER ;
Well here is the problem...I want to update the inventory table at my database which includes
Sale(ProductID,Quantity,Price)
Invlevel(ProductID,Quantity)
I want to use triggers for this update. I have to use 2 triggers (I think). 1 at the sale tables which will be something like
CREATE TRIGGER `sale_AINS` AFTER INSERT ON sale FOR EACH ROW
begin
update Invlevel set quantity = Invlevel.quantity-"sale.quantity" where
Invlevel.ProductID = "sale.ProductID";
END
with this trigger, when a sale comes up, I want to adjust the inventory level at the product which the sale came to. However, even though this trigger has no errors and runs properly when I insert into sale table, it doesn't make any changes at the Invlevel table and I don't know why ( :# ).
Moreover, I made the trigger at the Invlevel table like that
CREATE TRIGGER `invlevel_AUPD` after UPDATE on invlevel FOR EACH ROW
if invlevel.quantity < 20
begin
insert into orders
(select productid,amount from reorder where reorder.productid = invlevel.productid )
end
*(orders,reorder are other tables)
It says to me I have syntax error which I don't know what it is and also even if I find it I can't even check the logic because the other trigger isn't even working... Any thought or help about it would be really helpful.
Try
First trigger
CREATE TRIGGER sale_AINS
AFTER INSERT ON sale
FOR EACH ROW
UPDATE invlevel
SET quantity = quantity - NEW.quantity
WHERE productid = NEW.productid;
In this trigger you don't need BEGIN END block since there is only one statement. In order to access column values or a row(s) that being inserted you need to use NEW keyword.
And the second one
DELIMITER $$
CREATE TRIGGER invlevel_AUPD
AFTER UPDATE ON invlevel
FOR EACH ROW
BEGIN
IF NEW.quantity < 20 THEN
INSERT INTO orders (productid, amount)
SELECT productid, amount
FROM reorder
WHERE productid = NEW.productid;
END IF;
END$$
DELIMITER ;
In the second trigger IF statement was out of BEGIN END block and syntax for IF was wrong. It should be IF ... THEN ... END IF;. And the same problems with a NEW keyword.
Here is SQLFiddle demo
You can put your IF condition into WHERE clause and make it more succinct like this
CREATE TRIGGER invlevel_AUPD
AFTER UPDATE ON invlevel
FOR EACH ROW
INSERT INTO orders (productid, amount)
SELECT productid, amount
FROM reorder
WHERE productid = NEW.productid
AND NEW.quantity < 20;
Here is updated SQLFiddle demo