Reputation: 21
Maybe the coffee hasn't kicked in but I'm having trouble wrapping my head around how to accomplish a SQL update. Essentially, I have 3 tables and I'm attempting to update a field in table1 with data in table2 based off criteria in table 3.
My 3 tables with sample data:
tblInvoiceDetail
keyID InvoiceNumber ItemID Qty Price
--------------------------------------------------------
1 200123 100001 4 400
2 200123 100002 1 10
3 200321 100001 1 100
4 200555 100002 2 20
5 200444 100003 4 20
tblInvoices
keyID InvoiceNumber InvoiceDate CustomerID InvoiceTotal
--------------------------------------------------------------------------
1 200123 3/15/19 456123 410
2 200321 5/31/19 123456 100
3 200555 6/30/19 111222 120
4 200444 6/31/19 111222 20
tblItemUpdate
keyID OldItem NewItem
----------------------------------
1 100001 999001
2 100002 999002
3 100003 999003
Here's an UPDATE
statement that I tried but it would not update all the records I expected to.
UPDATE
tblInvoiceDetail
SET
tblInvoiceDetail.ItemID = tblItemUpdate.NewItem
FROM
tblInvoiceDetail
INNER JOIN
tblItemUpdate ON tblInvoiceDetail.ItemID = tblItemUpdate.OldItem
INNER JOIN
tblInvoices ON tblInvoiceDetail.InvoiceNumber = tblInvoices.InvoiceNumber
WHERE
tblInvoices.InvoiceDate < '2019-06-25'
I suspect the problem is in my JOINs so it is not matching all the records I'm wanting.
I want to change the ItemID in tblInvoiceDetail and I want it to find the match in tblItemUpdate.OldItem and change it to the value in tblItemUpdate.NewItem. However, I only want to update the ItemID if tblInvoices.InvoiceDate is prior to 6/25/19.
So, with my sample data in tblInvoiceDetail, only keyIDs 1, 2, and 3 would need to be updated.
I have a lot of records in my live database so I can point to 1 particular thing that didn't work. I just found several invoices that I thought should have changed but didn't.
Upvotes: 1
Views: 72
Reputation: 17915
The standard way to write this is by using subqueries:
UPDATE tblInvoiceDetail
SET ItemID = (SELECT NewItem FROM tblItemUpdate WHERE OldItem = tblInvoiceDetail.ItemID)
WHERE InvoiceNumber IN (
SELECT id.InvoiceNumber
FROM tblInvoiceDetail AS id INNER JOIN tblItemUpdate AS iu ON id.ItemID = iu.OldItem
WHERE id.InvoiceDate < CAST('2019-06-25' AS DATE)
);
Ezlo already pointed out the problem when joining to the updated table created multiple rows.
EDIT:
Looking closer at your data I also see that you have a bigger problem matching up ItemID
s with the correct invoices. The primary key in tblInvoiceDetail
is a compound of both InvoiceNumber
and ItemID
yet you don't appear to have that information in the list from tblItemUpdate
.
Since your sample data includes an invalid date of June 31 it's natural to wonder if a string comparison issue is at play. The primary key issue would potentially rope in more invoices than intended so it wouldn't explain your problem described as fewer rows updating than expected.
Upvotes: 1
Reputation: 14189
I want to change the ItemID in tblInvoiceDetail and I want it to find the match in tblItemUpdate.OldItem and change it to the value in tblItemUpdate.NewItem
So far:
UPDATE D SET
ItemID = U.NewItem
FROM
tblInvoiceDetail AS D
INNER JOIN tblItemUpdate AS U ON D.ItemID = U.OldItem
However, I only want to update the ItemID if tblInvoices.InvoiceDate is prior to 6/25/19.
You can check for existence with EXISTS
:
UPDATE D SET
ItemID = U.NewItem
FROM
tblInvoiceDetail AS D
INNER JOIN tblItemUpdate AS U ON D.ItemID = U.OldItem
WHERE
EXISTS (SELECT NULL FROM tblInvoices AS I WHERE
I.InvoiceNumber = D.InvoiceNumber AND -- Link the invoice to update (D) to the invoice table (I)
I.InvoiceDate < '2019-06-25')
Be careful with your InvoiceDate
data type. It should be DATE
(or DATETIME
) and not VARCHAR
, because it will be bring trouble whenever you compare it against a value otherwise ('6/25/19'
and '2019-06-25'
are both dates but they are completely different strings).
Also beware of the existence of multiple rows with the same OldItem
value on tblItemUpdate
, as you might be joining a particular row from tblInvoiceDetail
against N from the tblItemUpdate
in which case the final NewItem
value that will be updated is indetermined.
Upvotes: 0