Trigger after update orderline - sql

im trying to create a trigger to set a order date to system date once all the items in the order have been dispatched.
we have a OrderHeader table with order_id and order_completed. This will have 1 row per order
We then have OrderLine table with orderline_order with a foreign key to OrderHeader. This table can have multiple rows for the same orderline_order (so multiple items for a order)
Orderline has a field in it orderline_fulfilled which is either a 'Y' or 'N'
I want a trigger to update the order_completed to sysdate when all orderline_fulfilled are 'Y' for that order. I currently got to the statement below, but how would I ensure im only checking the orderline_fulfilled is 'Y' for that orderline_order if that makes sense?
create or repalce trigger Order_complete
after update of Orderline_fulfilled
on val354_orderline
begin update val354_orderheader join val354_orderline on (Order_id = Orderline_order)
set Order_completed = sysdate
where Orderline_fulfilled

I think you want something like:
CREATE OR REPLACE TRIGGER ORDER_COMPLETE
AFTER UPDATE OF ORDERLINE_FULFILLED
ON VAL354_ORDERLINE
BEGIN
UPDATE VAL354_ORDERHEADER h
SET h.ORDER_COMPLETED = 'Y'
WHERE h.ORDER_COMPLETED = 'N' AND
NOT EXISTS (SELECT *
FROM VAL354_ORDERLINE l
WHERE l.ORDERLINE_ORDER = h.ORDER_ID AND
l.ORDERLINE_FULFILLED = 'N');
END ORDER_COMPLETE;
Give that a try.

Related

Update column value of a table when the value of another table changes

I have 3 tables (Inventory, OrderMaster, OrderDetail). In the table Inventory I have ID_PRODUCT and quantity_inventory columns. In the table OrderMaster I have ID_ORDER and ID_STATE_OF_ORDER (all rows are 3 at the start). Last, but not least, inthe table OrderDetail I have ID_ORDER, ID_PRODUCT and quantity_ordered.
I need a trigger that when the ID_STATE_OF_ORDER in OrderMaster changes to 1, then quanity_inventory in the table Inventory will be the current amount minus quantity_ordered
The current trigger I have is
create or replace trigger Inventory_switch
AFTER UPDATE on OrderMaster
Begin
UPDATE Inventory
SET quantity_inventory =
(SELECT Inventory.quantity_inventory - OrderDetail.quantity_ordered
FROM Inventory, OrderDetail, OrderMaster
WHERE Inventory.ID_PRODUCT = OrderDetail.ID_PRODUCT AND
OrderMaster.ID_ORDER = OrderDetail.ID_ORDER AND
OrderMaster.ID_STATE_OF_ORDER = 1);
End;
This code updates all the rows in Inventory regardless of the conditions I've entered.
Please, I would apreciate any help. Thanks in advance.
As it is Oracle, then:
you're missing the FOR EACH ROW clause (so that you'd update rows which are related to id_order whose values have been updated)
reference to :new pseudorecord
when clause, so that you wouldn't update anything if state of order isn't 1
exists clause, so that you wouldn't update the whole table but only affected rows
Something like this:
create or replace trigger inventory_switch
after update of id_state_of_order on ordermaster
for each row
when (new.id_state_of_order = 1
and
nvl(old.id_state_of_order, 0) <> 1
)
begin
update inventory i
set
i.quantity_inventory = i.quantity_inventory -
(select sum(od.quantity_ordered)
from orderdetail od
where od.id_product = i.id_product
and od.id_order = :new.id_order
)
where exists
(select null
from orderdetail od
where od.id_product = i.id_product
and od.id_order = :new.id_order
);
end inventory_switch;
/

Run update statement on inserted rows only through a trigger

I have created a Trigger to update a custom date [Invoice.ContractStartDate] on an invoice record when added to the Invoice Table [InvoiceTable].
The Trigger below works but I would like this to run for Inserted records only and avoid using the WHERE clause for DateTimeCreated.
I will still require the WHERE clause for Contract.Days <> ' '
Is this possible using using AFTER INSERT or INSTEAD OF INSERT?
CREATE TRIGGER UpdateContractStartDate ON InvoiceTable
FOR INSERT AS
UPDATE InvoiceTable
SET InvoiceTable.ContractStartDate = InvoiceTable.InvoiceDate + Contract.Days
FROM Contract
INNER JOIN InvoiceTable
ON InvoiceTable.ContractID = Contract.ContractID
WHERE (CAST(InvoiceTable.DateTimeCreated AS DATE) = CAST(GETDATE() AS DATE))
AND (Contract.Days <> '')
You don't provide any information on your table schema, but assuming you have a unique key "Id"
The typical syntax would be
Update it set
it.ContractStartDate = it.InvoiceDate + c.Days
from inserted i
join InvoiceTable it on it.Id=i.Id
join Contract c on c.ContactId=it.ContractId and c.Days <> ''

TSQL: Prevent Nulls update over existing data

I have 2 tables:
Orders (Table I update and want keep existing data, and prevent overwriting with nulls)
WRK_Table (This table is identical to Orders but can not guarantee all columns will have data when running update)
PK column 'Master_Ordernum'
There are many columns in the tables, the WRK_Table will have the PK, but data in other columns can not be counted on.
I want the WRK_Table to update Orders only with actual data and not Nulls.
I was thinking along this line:
UPDATE [Orders]
SET [Status] = CASE WHEN S.[Status] IS NOT NULL THEN S.[Status] END
FROM [WRK_TABLE] S
WHERE [Orders].[Master_Ordernum] = S.[Master_Ordernum]
The existing data in Orders is being updated with nulls
does this help?
update orders set name = work.name
from orders
inner join work on orders.id = work.id and work.Name is not null
Not the same col / table name but you should get the idea
EDIT
Your SQL, NOT TESTED
UPDATE Orders
SET [Status] = WRK_Table.[Status]
FROM [Orders]
inner join WRK_Table on [Orders].[Master_Ordernum] = [WRK_Table].[Master_Ordernum] and WRK_Table.[Status] is not null
If you want to test and undo your data just do something like (assuming you don't have 100s of rows)
begin tran
/* .. SQL THAT UPDATES ... */
select * from orders // review the data
rollback tran // Undo changes
If you're going to use a Case statement, you need to include an else to prevent it from just inserting that null. Try this - if the work table has a null, let it just overwrite the value with the existing value.
UPDATE [Orders]
SET [Status] = CASE WHEN S.[Status] IS NOT NULL THEN S.[Status] else [Orders].[Status] END
FROM [WRK_TABLE] S
WHERE [Orders].[Master_Ordernum] = S.[Master_Ordernum]
Not sure if you can use
Update my_table set col = ISNULL(#newval,#existingval) where id=#id
https://msdn.microsoft.com/en-us/library/ms184325.aspx

T-SQL Trigger - Updating a Table using a separate table, multi-row insert possible

I'm new to triggers and am working on setting up a trigger to update a table (REQ_L) when a record is inserted there that meets specific parameters. The value to update in REQ_L is pulled from a separate table that has a matching key.
create table REQ_L (item_number varchar(20),
commodity_code varchar(20),
vendor_id varchar(20),
item_source varchar(20));
create table XREF_C (item_number varchar(20),
commodity_code varchar(20),
xref_type varchar(20));
I'd like it for when a record is inserted into REQ_L, if it meets the criteria in the trigger it will be update the COMMODITY_CODE from REQ_L with the COMMODITY_CODE in XREF_C using the ITEM_NUMBER as the key.
No longer locking and switched over to using the inserted tables. The good news is no more deadlock, the bad is that it's still not updating the table. Updated SQL Trigger attempt:
CREATE TRIGGER WBM
ON REQ_L
AFTER INSERT
AS
IF EXISTS (SELECT * FROM inserted WHERE VENDOR_ID = 'W7315'
AND ITEM_SOURCE = 'XML'
AND COMMODITY_CODE NOT LIKE '%-%')
BEGIN
UPDATE REQ_L
SET COMMODITY_CODE = (SELECT distinct CODE_2
FROM XREF_C xc, inserted i
WHERE i.ITEM_NUMBER = xc.CODE_1
AND xc.XREF_TYPE = 'WBM')
FROM XREF_C xc, inserted i
WHERE i.ITEM_NUMBER = xc.CODE_1
END
GO
Try simplyfing your query structure. I still don't know what CODE_1 and CODE_2 are but this worked for me.
ALTER TRIGGER [dbo].[WBM]
ON [dbo].[REQ_L]
AFTER INSERT
AS
UPDATE REQ_L
SET commodity_code = xc.commodity_code FROM INSERTED i INNER JOIN XREF_C xc ON i.Item_Number=xc.item_number
AND
xc.xref_type = 'WBM'
AND
i.VENDOR_ID = 'W7315'
AND
i.ITEM_SOURCE = 'XML'
AND
i.COMMODITY_CODE NOT LIKE '%-%'
Remember, IF statements belong in C# and Visual Basic - if you are using them in SQL you are not writing your queries with a dataset mentality. Most of the time that is; sometimes they can't be avoided.
I agree with the general comments above, but I'm thinking the logic your using looks dodgy. You have:
UPDATE REQ_L
SET COMMODITY_CODE = (SELECT distinct CODE_2
FROM XREF_C xc, inserted i
WHERE i.ITEM_NUMBER = xc.CODE_1
AND xc.XREF_TYPE = 'WBM')
FROM XREF_C xc, inserted i
WHERE i.ITEM_NUMBER = xc.CODE_1
Well I may be wrong, but I can't help thinking that the table you're updating should appear in the from clause of the statement.
How about this:
UPDATE rl
SET Commodity_Code = x.Code_2
FROM Req_L rl
INNER JOIN Inserted i ON --limit the join clause to the cols that have been inserted
rl.item_number = i.item_number and
rl.commodity_code = i.commodity_code and
rl.vendor_id = i.vendor_id and
rl.item_source = i.item_source
INNER JOIN XREF_C x ON L.item_number = x.item_number
WHERE x.xref_type = 'WBM'

PLSQL - Triggers: Cannot modify a column which maps to a non key-preserved table

What I'm suppose to do is use a trigger to update the quantity sold in the inventory table when an order is placed in the concessions_sold table(an insert is used). I admit that I suck at PLSQL so I'm not sure if I'm going about this the right way. The error I'm getting is:
SQL> insert into concessions_sold
2 values(33, 104, '26-Apr-09', 50);
insert into concessions_sold
*
ERROR at line 1:
ORA-01779: cannot modify a column which maps to a non key-preserved table
My code:
create or replace trigger LabEx5_1 after insert on Concessions_sold
for each row
begin
if inserting then
update
(
select i.quantity
from inventory i, concessions_sold cs, concession c
where i.inventory_id = c.inventory_id and c.concession_id = cs.concession_id
)
set quantity = :new.quantity;
end if;
end LabEx5_1;
/
First of all if you use a "For Each Row" trigger then you MUST NOT operate on the whole table, just one row, so
select i.quantity
from inventory i, concession c
where i.inventory_id = c.inventory_id and c.concession_id = cs.concession_id
should be changed to
select i.quantity
from inventory i, concessions_sold cs, concession c
where i.inventory_id = c.inventory_id and c.concession_id = :new.concession_id
Second, the update should be something like:
update inventory
set quantity = :new.quantity
where inventory_id = (
select inventory_id from concession c where concession_id = :new.concession_id
) ;
So the trigger should look like this:
create or replace
trigger LabEx5_1 after insert on Concessions_sold
for each row
begin
if inserting then
update inventory
set quantity = :new.quantity
where inventory_id = (
select inventory_id from concession c
where concession_id = :new.concession_id
) ;
end if;
end LabEx5_1;
You're trying to update a join view in your trigger, which has several constraints on when this can be done; see the Oracle documentation for more details.
This UPDATE should do what you're trying to achieve:
UPDATE inventory i
SET i.quantity = :new.quantity
WHERE i.inventory_id =
(SELECT c.inventory_id
FROM concessions c
WHERE c.concession_id = :new.concession_id)
Couple of things:
the "after insert" and "If (inserting)" are redundent. Remove the "If (inserting)" it's unnecessary since your trigger is limited to AFTER INSERT. Just adds more code to read.
It seems you are trying lower your inventory when something is sold. I don't see that you actually do that.
This is embeded query doesn't have a key associated with it. (This is were your error message comes from).
select i.quantity
from inventory i, concessions_sold cs, concession c
where i.inventory_id = c.inventory_id and c.concession_id = cs.concession_id
You don't have a where clause and your inline-select doesn't limit the rows coming back from the inventory table. If you do get this to work, you are going to update every row in your Inventory table.
To make your actual update clause work.
UPDATE (
SELECT **i.inventory_id**, i.quantity
FROM Inventory i
, Concessions_sold cs
, Concessions c
WHERE i.inventory_id = c.inventory_id
AND c.concession_id = **:NEW.concession_id**
)
SET quantity = :new.quantity
Now it works there are a few problems:
1. Linking table is unnecessary.
2. The inline SQL is making this UPDATE statement more difficult to read and hence more difficult to modify in the future.
I would be much more explicit:
UPDATE Inventory
SET quatity = quanaity - :new.quanity
WHERE inventory_id IN (
SELECT inventory_id
FROM Conessions c
JOIN c.concession_id = :NEW.concession_id
)
Obviously there's no checks to see that inventory quantity actually exists, something else you might want to take into consideration.
So your new trigger would look like this.
CREATE or REPLACE TRIGGER LabEx5_1 AFTER INSERT ON Concessions_sold
FOR EACH ROW
BEGIN
UPDATE Inventory
SET quatity = quanaity - :NEW.quanity
WHERE inventory_id IN (
SELECT inventory_id
FROM Conessions c
JOIN c.concession_id = :NEW.concession_id
);
END LabEx5_1;