TSQL: Prevent Nulls update over existing data - sql

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

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;
/

PL/SQL Update Query

Attempting to update a table I have created with null values from another table I have created in PL/SQL:
I was able to utilize the below update in SQL Server but am running into issues within PL/SQL (dont ask why I am running it in both)
Overall_Inventory = Table created with some populated values and some null valuse; this is the table requiring updates to those null values
task_table = Table also created, but contains value needing to be updated into T1
update dbh.overall_inventory
set dbh.overall_inventory.case_due_date = tsk.TASK_ACTION_TIMESTAMP
from dbh.overall_inventory,
(SELECT tsk.INQ_KEY,
min(tsk.TASK_ACTION_TIMESTAMP) as TASK_ACTION_TIMESTAMP
FROM dbh.task_table tsk
inner join dbh.overall_inventory Inv
on tsk.INQ_KEY = inv.inq_key
where tsk.ACTION_CD = '324'
group by tsk.INQ_KEY
) tsk
where tsk.INQ_KEY = dbh.overall_inventory.inq_key`
Oracle doesn't support from clause in the update statement. In this situation merge statement can be used.
merge into overall_inventory oi
using (select tsk.inq_key,
min(tsk.task_action_timestamp) as task_action_timestamp
from task_table tsk
join overall_inventory Inv
on tsk.inq_key = inv.inq_key
where tsk.action_cd = '324'
group by tsk.inq_key) tsk
on (tsk.inq_key = oi.inq_key )
when matched then
update
set case_due_date = tsk.task_action_timestamp
where case_due_date is null -- as I understood only NULL values
-- need to be updated
Note: Not tested because no sample data and desired result were provided.
I think you're looking for update over a select:
UPDATE (
  SELECT product_id, category_id
  FROM product) st
SET st.category_id = 5
WHERE st.category_id = 4;

Trigger after update orderline

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.

T-SQL Query to check if related col is true and update another table col

I have this 2 tables SupplierOrder and SupplierOrderDetails which are linked by SupplierOrder PK. Now I have this col called isComplete in the SupplierOrder table which I want o update to true once all the values in the SupplierORderDetails table's isComplete are all true for that supplierOrder ID. Please see the attachment for the tables. I have tried myself with this query but I think it could be a better way or more efficient.
SELECT 1
FROM supplierOrder so
inner JOIN supplierOrderdetails sod
ON so.id = sod.supplierOrderID
WHERE so.id = 1
AND sod.isComplete= 1
This should work, I maynot have correct table names but this should work if u change it
UPDATE suplierorder
SET iscomplete = 'true'
WHERE id IN (SELECT suplierorderid
FROM (SELECT suplierorderid,
--case statement to set to 0 if complete and 1 if not complete (i.e any other value null or false)
Sum(CASE
WHEN iscomplete = 'true' THEN 0
ELSE 1
END) AS complete
FROM suplierorderdetails
--make sure we only update the new ones and makes sure that your select records are limited to Just not complete records, so if your tables grow this will make your update statement doesn't take a lot of time
WHERE suplierorderid IN (SELECT id
FROM suplierorder
WHERE iscomplete IS NULL)
--I am grouping on suplierorderid so that we can add all the iscomplete status of each suplierorderid column
GROUP BY suplierorderid) A
--now that the inner query outputs suplierorderid and complete status which will be 0 if everything is complete we are writing below condition
WHERE complete = 0)
All we need is to find supplierOrderID where MIN(isComplete)=1. So it means that ALL isComplete=TRUE
UPDATE supplierOrder SET isComplete=1
WHERE id in
(
SELECT supplierOrderID
FROM supplierOrderdetails
GROUP BY supplierOrderID
HAVING MIN(CAST(isComplete as Int))=1
)
AND
(
(isComplete is NULL ) OR (isComplete = 0)
)
SQLFiddle demo
PS: Since isComplete is a BIT type field you can't use MIN(isComplete) but you can use MIN(CAST(isComplete as Int))

Problems inserting new data into SQL Server table

I am trying to do an if else insert into one table from another (a table type).
I am having problems where basically the first time the script runs it adds all data into the table OK but then if something is added to the source data afterwards, it does not add the new record and I don't know why.
I can't include the exact code but it looks like this...
UPDATE CUSTOMER
Set Target.Desc = Source.Desc
From #source source
WHERE Target.AccountNumber = Source.AccountNumber
IF ##ROWCOUNT=0
INSERT INTO CUSTOMER(AccountNumber, Desc)
SELECT Source.AccountNumber, Source.Desc
FROM #Source Source
I have also tried a traditional if else insert but it had the same results.
Can you see anything wrong that might be stopping the newly added records from being inserted?
Your current code will only work correctly if #source contains either all existing or all new rows.
You can use MERGE when this is not the case
MERGE CUSTOMER AS target
USING #source AS source
ON ( target.AccountNumber = source.AccountNumber )
WHEN MATCHED THEN
UPDATE SET [Desc] = source.[Desc]
WHEN NOT MATCHED THEN
INSERT (AccountNumber, [Desc])
VALUES (AccountNumber, [Desc]);
How about doing this instead of using ##ROWCOUNT
-- update existing customers
UPDATE c
SET c.Desc = Source.Desc
FROM #source source
INNER JOIN CUSTOMER c ON c.AccountNumber = Source.AccountNumber
-- insert new customers
INSERT INTO CUSTOMER(AccountNumber, Desc)
SELECT Source.AccountNumber, Source.Desc
FROM #Source Source
LEFT JOIN CUSTOMER c ON Source.AccountNumber = c.AccountNumber
WHERE c.AccountNumber IS NULL
-- update all existing rows
update c set
c.Desc = s.Desc
from CUSTOMER c
join #source s on s.AccountNumber=c.AccountNumber
-- insert all missing rows
insert into CUSTOMER (AccountNumber, Desc)
select s.AccountNumber, s.Desc
from #Source s
where not exists(
select *
from CUSTOMER c
where c.AccountNumber=s.AccountNumber
)
The first time, there is no data in your target so ##rowcount is 0.
Next time, the update updates all data and ##rowcount is not 0 and you get no data inserted.
You should not use ##rowcount but do what Andrew suggest: do both UPDATE and INSERT
or MERGE (do both in one statement)
##ROWCOUNT value contains the count of affected rows. the insert statement works only if all the records are new. and it does not go for updation. if any of the record got updated, it would not go for insertion even the source contains new records
If your requirement is to update existing records and Insert New records from source , you can use the below code.
-- update existing Rows
UPDATE CUSTOMER
SET CUSTOMER.Desc = SOURCE.Desc
from #SOURCE Source
WHERE Source.AccountNumber=CUSTOMER.AccountNumber
-- Insert New Data
INSERT INTO CUSTOMER (AccountNumber, Desc)
SELECT s.AccountNumber, s.Desc
FROM #Source Source
WHERE not exists( SELECT 1
FROM CUSTOMER
WHERE CUSTOMER.AccountNumber=Source.AccountNumber)