I am creating a room reservation in php.
I have two tables:
table RESERVE
reserve_id
room_id
room_reserve_qty
checkout
table ROOM
room_id
room_qty
when the "checkout" date reached the date today,that row in the reserve table will be deleted.Actually I already have the event for that :
DROP EVENT `auto_delete_chckout`;
CREATE DEFINER=`root`#`localhost`
EVENT `auto_delete_chckout`
ON SCHEDULE EVERY 1 MINUTE STARTS '2013-01-26 13:09:15'
ON COMPLETION NOT PRESERVE ENABLE DO
DELETE FROM reserve WHERE checkout <= CURDATE()
so my question is :
If a reservation is being deleted , its room_reserve_qty must be added in the room_qty in room table.
before you delete the records on table reserve, you need to update the records of table room first so you will know which room_id will be updated, eg
UPDATE room a
INNER JOIN reserve b
ON a.room_id = b.room_id
SET a.room_qty = a.room_qty + b.room_reserve_qty
WHERE b.checkout <= CURDATE();
DELETE FROM reserve WHERE checkout <= CURDATE();
full code:
DROP EVENT `auto_delete_chckout`;
DELIMITER $$
CREATE EVENT `auto_delete_chckout`
ON SCHEDULE EVERY 1 MINUTE STARTS '2013-01-26 13:09:15'
ON COMPLETION NOT PRESERVE ENABLE
DO
BEGIN
UPDATE room a
INNER JOIN reserve b
ON a.room_id = b.room_id
SET a.room_qty = a.room_qty + b.room_reserve_qty
WHERE b.checkout <= CURDATE();
DELETE FROM reserve WHERE checkout <= CURDATE();
END $$
DELIMITER ;
UPDATE
Since you mentioned that you are new, Event, I think, causes to much work on the server. A TRIGGER might be the other way. A Trigger is basically a block of code that is fired every time an event (before or after) is happening on the table, eg: INSERT, UPDATE and DELETE.
First of all you probably don't need to fire your event every minute, since you check only for a date part. You might want to do that once a day.
Secondly I would put updating room_qty logic in a trigger. That way no matter how you delete your reservation, your room_qty will be correct.
Your trigger might look like this
DELIMITER $$
CREATE TRIGGER reserve_before_delete BEFORE DELETE ON reserve
FOR EACH ROW BEGIN
UPDATE room
SET room_qty = room_qty + OLD.room_reserve_qty
WHERE room_id = OLD.room_id;
END;
$$
DELIMITER ;
Your DELETE code stays intact when you use a trigger.
Related
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.
Hello is possible INSERT row to table with expiration date and when the expiration date is reached so row are automatically deleted? Or i only must create one column with expiration date and when sorting checking this value for ignore?
Your need looks more like an Event
IF you want not want to add expiration date column than
CREATE EVENT delete_event ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
ON COMPLETION PRESERVE
DO BEGIN
DELETE FROM Your_table WHERE date>= logic for expiration_date ;
END;
otherwise
DELIMITER $$
CREATE EVENT Delete ON SCHEDULE EVERY 1 DAY
DO
BEGIN
DELETE FROM TABLE WHERE `date_expires` < CURRENT_TIMESTAMP();
END$$
DELIMITER
;
NOTE that MySQL Event Scheduler need to be enabled on your server:
SET GLOBAL event_scheduler = ON;
You cannot do this directly in the database. You can do this by scheduling an event or job that does the delete. You can schedule an event for each deletion.
I think a better approach, though, is to use a view:
create view v_t as
select t.*
from t
where expiration_date > now();
This ensures that the row is not available at the instant the expiration date is no longer in the future. You can then remove the rows at your leisure. Deleting rows can put a load on the database, so you might want to wait until the load is lighter.
I have this reservation table that has RESERVATION_ID , ROOM_NUM, Date_Start , Date_End and cost columns. what I want to do is insert all the columns except cost and fill the cost automatically.
delimiter //
CREATE TRIGGER upd_check before INSERT ON reservation
FOR EACH ROW
BEGIN
IF NEW.RESERVATION_COST = NULL THEN
SET NEW.RESERVATION_COST = 'timestampdiff(day, NEW.RESERVATION_STARTD, NEW.RESERVATION_ENDD)*70';
END IF;
END;//
delimiter ;
I wrote this trigger to do it, but whenever I press Apply to insert everything nothing is inserted to the RESERVATION_COST column.
why?
I would put this in a comment if I had enough reputation, but anyways. Triggers cannot act on the same table which activated them. Seems limiting, but we've had the same issue.
This link doesn't explicitly say this but it does say "in the associated table". Not the same: https://dev.mysql.com/doc/refman/5.0/en/triggers.html
You can't compare a value to NULL, you need to check if it IS NULL instead.
e.g.
IF NEW.RESERVATION_COST IS NULL THEN
I'm trying to create a trigger that will automatically increase the year column by 1 when the month column is 12, and then empty the month column.
But I don't understand triggers that well and I'm confusing myself in my attempts, so I was hoping someone could look over this code to see if it would work or suggest improvements:
CREATE TRIGGER aging BEFORE UPDATE ON dogs
FOR EACH ROW
DELETE FROM dogs WHERE month = 12;
UPDATE year SET year = year+1;
Thanks!
Two things to point out...
First, a trigger is clearly the wrong choice for what you want to do. Not only because the trigger can be avoided by calculating the age on the fly based on birth of date. But also, because a trigger only affects the rows that are affected by the corresponding statement. Don't be fooled by the FOR EACH ROW. You write something like
UPDATE table SET whatever = whatever WHERE month = 12;
and all the rows where month = 12 is true are affected. What you seem to want to do, is to update the whole table to check if in some rows your condition is true. Not only is this a performance nightmare, you are also restricted to one trigger (per event) per table. Meaning you can have i.e. one BEFORE UPDATE and 1 AFTER UPDATE but not 2 BEFORE UPDATE.
The second thing to note is, that you can't issue an UPDATE statement in an UPDATE trigger. This would cause an infinite loop :)
Instead you use the aliases NEW and OLD. NEW refers to the value of a column given by the UPDATE statement and OLD refers to the value of the column before the UPDATE statement was executed.
In your case (althoug it's hopefully clear by now, that you shouldn't use the trigger in this case), one would write the trigger like this:
Given this initial statement
UPDATE myTable SET whatever = whatever;
which updates the whole table, this trigger
DROP TRIGGER IF EXISTS [whatever you call this thing];
DELIMITER ##
CREATE TRIGGER aging BEFORE UPDATE ON dogs
FOR EACH ROW
IF (month = 12) THEN /*month refers to the column here, not a variable like in Gordon's answer*/
SET NEW.year = OLD.year+1;
SET NEW.month = 1;
END IF;
END ##
would update the columns correctly.
I've never created a trigger before, but I just read through the docs. This is my attempt...
DELIMITER ||
DROP TRIGGER ID EXISTS [whatever you call this thing]
||
DELIMITER ##
CREATE TRIGGER aging BEFORE UPDATE ON dogs
FOR EACH ROW
DECLARE month integer;
IF (month = 12) THEN
-- DELETE FROM dogs WHERE month = 12;
-- this will delete the record; probably not what you want
UPDATE year SET year = year+1;
UPDATE month SET month = NULL;
END IF;
END;
##
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