I'm trying to write a trigger for a database but feel a bit lost. This is what I want the trigger to do: When there have been changes made to shipments (so when a new item has been shipped) I want to alter the value stock in another relation also called stock by subtracting 1, so that the two relationships correlate.
Any ideas? Thank you in advance!
The old and new items refer to to the shipment table. Since the stock fields are in the stock table, you need to explicitly update it. Similarly, you will want to fetch the count and assess its validity.
CREATE FUNCTION decstock() RETURNS trigger as $pname$
qty integer;
BEGIN
--Get the current count
SELECT stk.stock
INTO qty
FROM stock stk
WHERE stk.isbn=old.isbn;
--Validate count
IF (qty = 0) then
raise exception 'There is no stock to ship';
ELSE
--Update valid stock
UPDATE stock stk
SET stk.stock = stk.stock - 1
WHERE stk.isbn = old.isbn;
END IF;
RETURN NEW;
END;
$pname$ LANGUAGE plpgsql;
Related
I have the following snippet of an ER-diagram.
Whenever "order_item" is updated (i.e. when an item has been added to a 'shopping cart'), I want to decrement "Quantity" in the table "itemsinstock".
I know the syntax of a trigger (well, MySQL can also generate it) but I don't know how to do it. "order_item" needs to read ItemID from "itemsinstock" and based on that ID, it needs to decrement the quantity for that specific item. Is this possible?
Edit:
This is what I have now:
CREATE DEFINER=`root`#`localhost` TRIGGER
`orderdb`.`itemsinstock_AFTER_INSERT`
AFTER INSERT ON `order_item`
FOR EACH ROW
BEGIN UPDATE itemsinstock
SET Quantity = Quantity - order_item.itemQuantity WHERE itemID = ItemID; END
It gives me an error with "order_item.itemQuantity" .... It worked with "-1" but obviously I want it to decrement based on how many "itemQuantity" is. How do I do this?
Pretty close
CREATE DEFINER=`root`#`localhost` TRIGGER
`orderdb`.`itemsinstock_AFTER_INSERT`
AFTER INSERT ON `order_item`
FOR EACH ROW
BEGIN
UPDATE itemsinstock
SET Quantity = Quantity - NEW.itemQuantity WHERE itemID = NEW.id;
END
notice how order_item (which isn't defined) is being replaced by NEW which represents the row that was inserted. Also as a side note since this is a single statement you don't need begin end blocks
I need some help with getting the syntax right to define a trigger in PHPmyAdmin.
What I have:
2 tables - invoice and invoiceitem
tbl_invoice has a field 'Total' which should show the sum of the 'Extended' price of the table invoiceitem
tbl_invoiceitem has 2 triggers that update the 'Extended' before_insert and before_update
What I try to accomplish:
Calculate the sum of all items for an invoice and update the 'Total' price in tbl_invoice after either new items are inserted or if the price or quantity for an existing item was updated.
I try to do this in PHPmyAdmin.
The error message is
I hope somebody can give mt a hint into the right direction. Just started with triggers and don't seem to find solution with a couple of days searching the internet.
Thank you for help in advance.
Cheers, Oliver
I can see 2 syntax errors in your code:
The delimiter commands should be outside of the trigger definition, not inside of it. Phpmyadmin should take care of this.
The commands within the begin ... end block should be terminated by semicolon (;), not by whatever you provide in the delimiter command.
I did not check if your sql commands within the trigger make sense, but the where condition of the set command does not seem right.
Ok, found a work around:write the full create trigger statement in a file and import with PHPmyAdmin. As 'Shadow' pointed out there was also a problem in the where conditions.
Below the corrected triggers that worked in my scenario.
There is a lot of examples on the net to get triggers done with the mysql client. This way you can use the exact syntax that you would type into a client and than import into PHPmyAdmin in case you can't reach the server your using with a command shell client.
Hope this helps other newbies.
Cheers, Oliver
-- after_insert trigger for InvoiceItem to Calculate the Total in Invoice
------------------------------------------------------------------------
DELIMITER //
CREATE TRIGGER `InvoiceItem_After_Insert` AFTER INSERT ON `invoiceItem`
FOR EACH ROW
BEGIN
SET #InvoiceNumber = NEW.InvoiceFK;
SET #ItemTotal = (SELECT SUM(Extended) FROM InvoiceItem WHERE InvoiceFk = #InvoiceNumber);
UPDATE Invoice SET Total = #ItemTotal WHERE id = #InvoiceNumber;
END
//
DELIMITER ;
-- after_update trigger for InvoiceItem to Calculate the Total in Invoice
------------------------------------------------------------------------
DELIMITER //
CREATE TRIGGER `InvoiceItem_After_Update` AFTER UPDATE ON `invoiceitem`
FOR EACH ROW
BEGIN
SET #InvoiceNumber = NEW.InvoiceFK;
SET #ItemTotal = (SELECT SUM(Extended) FROM InvoiceItem WHERE InvoiceFk = #InvoiceNumber);
UPDATE Invoice SET Total = #ItemTotal WHERE id = #InvoiceNumber;
END
//
DELIMITER ;
-- after_delete trigger for InvoiceItem to Calculate the Total in Invoice
----------------------------------------------------------------------
DELIMITER //
CREATE TRIGGER `InvoiceItem_After_Delete` AFTER DELETE ON `invoiceItem`
FOR EACH ROW
BEGIN
SET #InvoiceNumber = OLD.InvoiceFK;
SET #ItemTotal = (SELECT SUM(Extended) FROM InvoiceItem WHERE InvoiceFk = #InvoiceNumber);
UPDATE Invoice SET Total = #ItemTotal WHERE id = #InvoiceNumber;
END
//
DELIMITER ;
-----------------------------------------------------------------
The next 2 triggers are just single statement and are calculate the 'Extended' column in the InvoceItem table
---------------------------------------------------------------------
-- Calculate new 'Extended' price before insert
CREATE TRIGGER `InvoiceItem_Before_Insert` BEFORE INSERT ON `invoiceitem`
SET NEW.Extended = ROUND(NEW.Quantity * NEW.Price,2)
-------------------------------------------------------------------
-- Calculate new 'Extended' price before update
CREATE TRIGGER `InvoiceItem_Before_Update` BEFORE UPDATE ON `InvoiceItem`
FOR EACH ROW
SET NEW.Extended = ROUND(NEW.Quantity * NEW.Price,2);
I have table called company. Structure as follows:
company
-----------------------------
company_id integer
company_name varchar
fk_company_type varchar
created_date date
fk_company_type is foreign key with the following values:
HQ
SITE
CUSTOMER
SUPPLIER
My issue I only want one record in company table to be HQ (HeadQuarters). Therefore I need a trigger that will count how many HQ in the company table. If it the count returns 1 and the new record being inserted has value of fk_company_type = HQ then the insert is aborted.
Any help on the best way to do this will be much appreciated. Also I already have a trigger which generates a UUID for the company_id and date. Hopefully this does not effect what I am trying to achieve.
phpadmin trigger (time: BEFORE, event: INSERT)
BEGIN
SET NEW.company_id=UUID_SHORT();
SET NEW.created_date=current_timestamp();
END
I've tried the basics layout and got as far as this but it produces a syntax error, here is how far I got.
BEGIN
IF fk_company_type = "HQ" THEN
DECLARE valid_number int;
SELECT COUNT(*) into valid_number FROM company WHERE fk_company_type = "HQ";
IF valid_number > 0 THEN
-- some error message
END IF;
END IF;
SET NEW.company_id=UUID_SHORT();
SET NEW.created_date=current_timestamp();
END
A simple way to abort an insert is to set a value to an illegal one.
for example if the column is set to NOT NULL then set the value to NULL and the insert will fail.
The question/issue of how you tell people it has failed depends on your application.
I am trying to convert the following trigger from PL/SQL to MySQL
Especially i wanna know how to do this:
1. FOR quantity in 1..:new.product_quantity
2. FOR row IN ()
.
create or replace trigger "TRG_INSERT_BILL_PRODUCTS"
after insert on Bill_Products
for each row
begin
FOR quantity in 1..:new.product_quantity
LOOP
FOR row IN (
SELECT pa.article_id,pa.consist_quantity
FROM product_articles pa
WHERE pa.product_id=:new.product_id)
LOOP
update store
set store_quantity=store_quantity-row.consist_quantity
where article_id=row.article_id;
END LOOP;
END LOOP;
END;
Explanation of the trigger:
Store table has store.article_id and store.store_quantity for that article
Product_articles table has pa.product_id, pa.article_id (article that is consistent in the product), pa.consist_quantity (of the article)
So after inserting an product in bill, i want to find all his consisting articles and lower the store.store_quantity for that store.article_id, that would be product_quantity (how many products of that were added in the bill) * consist_quantity (of that article in the product)
FOR quantity in 1..:new.product_quantity
MySql hasn't FOR loop.
You can emulate it using WHILE loop:
Set quantity = 1
WHILE quantity <= :new.product_quantity DO
.....
statement_list
.....
Set quantity = quantity + 1
END WHILE
FOR row IN ( query ) LOOP ...
MySql doesn't support this kind of a loop, you must declare a cursor and process it:
DECLARE cursor_name CURSOR FOR
SELECT pa.article_id,pa.consist_quantity
FROM product_articles pa
WHERE pa.product_id=:new.product_id;
also declare a continue handler for this cursor, then explicitely open the cursor, fetch rows from it in a loop and close it.
Please refer to documentation: http://dev.mysql.com/doc/refman/5.6/en/cursors.html
to find how to use MySql cursors with examples.
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