Update multiple columns with Joining 2 tables in SQL - sql

Below is the code I am using for the update. The matching records between SRC and LKP table on the below condition are 31. But when I run the below update statement it's updating 200 records.Could you please suggest where could be the issue
UPDATE SRC src
SET (src.A,src.B,src.C,src.D) = (select lkp.A,lkp.B,lkp.C,'1'
from LKP lkp
inner join SRC
ON src.id_1=lkp.id_1
and src.CC=lkp.CC)

You have two issues:
You have no WHERE clause so all columns are updated.
You are referencing SRC in the subquery.
What I'm guessing you want is:
UPDATE SRC src
SET (src.A, src.B, src.C, src.D) =
(select lkp.A, lkp.B, lkp.C, '1'
from LKP lkp
where src.id_1 = lkp.id_1 and src.CC = lkp.CC
)
WHERE EXISTS (select 1
from LKP lkp
where src.id_1 = lkp.id_1 and src.CC = lkp.CC
);
For performance, you want in index on LKP(id_1, cc).

Related

How to solve this SQL specific merge problem

How to solve the error:
The MERGE statement attempted to UPDATE or DELETE the same row more than once. This happens when a target row matches more than one source row. A MERGE statement cannot UPDATE/DELETE the same row of the target table multiple times. Refine the ON clause to ensure a target row matches at most one source row, or use the GROUP BY clause to group the source rows.
merge CARD_ALERTS as t
using #tblAlerts as s
on (t.Id = s.AlertId and t.CardId = s.CardId)
when not matched by target
then insert(Id, ExternalCodeHolder, CardId, IsCardOwner, IBAN, PAN, MinAmount, Currency, ByEmail, BySMS, IssueDate, IsActive)
values(s.AlertId, s.ExternalCodeHolder, s.CardId, s.IsCardOwner, s.IBAN, s.PAN, s.MinAmount, s.Currency, s.ByEmail, s.BySMS, getdate(), 1)
when matched
then update set t.ByEmail = s.ByEmail, t.BySMS = s.BySMS, IsActive = 1, t.MinAmount = s.MinAmount
when not matched by source and t.Id=#AlertId
then update set t.IsActive = 3
As explained in the error message and in the comments, multiple rows of the source table correspond to the same row in the target one.
This will show you which rows of the target table have multiple rows from the source table that try to update them:
select t.Id,t.CardId,count(*) as [count]
from CARD_ALERTS as t
inner join #tblAlerts as s
on (t.Id = s.AlertId and t.CardId = s.CardId)
group by t.Id,t.CardId
having count(*)>1
This will also show you the multiple rows of the source table:
select t.*,s.*
from CARD_ALERTS as t
inner join #tblAlerts as s on (t.Id = s.AlertId and t.CardId = s.CardId)
inner join
(
select ca.Id,ca.CardId
from CARD_ALERTS as ca
inner join #tblAlerts as s
on (ca.Id = s.AlertId and ca.CardId = s.CardId)
group by ca.Id,ca.CardId
having count(*)>1
)tkey on t.Id=tkey.Id and t.CardId=tkey.CardId

If the record exists in target but doesn't exist in source, i need to delete it

So, i have two tables, the target table and the source one. I need to delete the rows that exists in the target table, but doesn't exists in the source table.
And the code:
MERGE INTO (SELECT id_car_bk, car_brand_bk, car_type_bk, new_car
FROM car_catalog_backup) CB
USING (SELECT id_car, car_brand, car_type FROM car_catalog) C
ON (CB.id_car_bk = b.id_car)
WHEN NOT MATCHED THEN
INSERT
(CB.id_car_bk, CB.car_brand_bk, CB.car_type_bk)
VALUES
(C.id_car, C.car_brand, C.car_type)
WHEN MATCHED THEN
UPDATE SET CB.car_brand_bk = C.car_brand;
You can use
DELETE car_catalog_backup b
WHERE not exists
( SELECT 0
FROM car_catalog c
WHERE b.id_car_bk = c.id_car );
or
DELETE car_catalog_backup b
WHERE b.id_car_bk not in
( SELECT c.id_car
FROM car_catalog c );
assuming car_catalog is the source, and car_catalog_backup is the target. The First one is preferable, since it's more performant.
If your aim is to find out with a MERGE statement similar to your case, then use the following
MERGE INTO car_catalog_backup a
USING (SELECT id_car, car_brand, car_type, car_brand_bk
FROM car_catalog
JOIN car_catalog_backup
ON id_car_bk = id_car
) b
ON (a.id_car_bk = b.id_car)
WHEN MATCHED THEN
UPDATE SET a.new_car = 1
DELETE
WHERE a.car_brand_bk != b.car_brand
WHEN NOT MATCHED THEN
INSERT
(id_car_bk, car_brand_bk, car_type_bk)
VALUES
(b.id_car, b.car_brand, b.car_type)
to delete the records matched for id columns ( a.id_car_bk = b.id_car ) but not matched for brand code columns ( a.car_brand_bk != car_brand ) as an example.
Demo
Delete from target
Where not exists
(
Select 1
From source
Where join of source and target
)
With a left join:
DELETE target
FROM target LEFT JOIN source
ON target.someid = source.otherid
WHERE source.otherid IS NULL;

ORA-38104: LHS of UPDATE SET contains the columns referenced in the ON Clause

I need to update the rows on (D.SELLER_ACCOUNT_ID = S.ACCOUNT_ID AND D.CATEGORY_ID = S.CATEGORY_ID_OLD).
How is it possible to correct the query below in Oracle?
MERGE INTO T_EVM_CLASSIFICATION D
USING (SELECT CATEGORY_ID_NEW, CATEGORY_ID_OLD, ACCOUNT_ID FROM DATA_TEMP) S
ON (D.SELLER_ACCOUNT_ID = S.ACCOUNT_ID AND D.CATEGORY_ID = S.CATEGORY_ID_OLD)
WHEN MATCHED THEN UPDATE SET D.CATEGORY_ID = S.CATEGORY_ID_NEW;
Move the "offending" condition from the ON clause to the WHERE clause:
MERGE INTO T_EVM_CLASSIFICATION D
USING (SELECT CATEGORY_ID_NEW, CATEGORY_ID_OLD, ACCOUNT_ID FROM DATA_TEMP) S
ON (D.SELLER_ACCOUNT_ID = S.ACCOUNT_ID)
WHEN MATCHED THEN UPDATE SET D.CATEGORY_ID = S.CATEGORY_ID_NEW
WHERE D.CATEGORY_ID = S.CATEGORY_ID_OLD;
If there is 1:1 relationship use a simple update:
update t_evm_classification d set category_id = (
select category_id_new
from data_temp s
where d.seller_account_id = s.account_id
and d.category_id = s.category_id_old )
The above update will nullify category_id if data in temp table is not present. To avoid this add where clause:
update t_evm_classification d
set category_id = ( select category_id_new
from data_temp s
where d.seller_account_id = s.account_id
and d.category_id = s.category_id_old )
where (d.seller_account_id, d.category_id) in
(select s.account_id, category_id_old from data_temp s)
There are a few possible workarounds which can be used to outsmart the parser, at least until Oracle 18c. One of them is to wrap your predicate in a row value expression predicate using an additional dummy column:
MERGE INTO T_EVM_CLASSIFICATION D
USING (SELECT CATEGORY_ID_NEW, CATEGORY_ID_OLD, ACCOUNT_ID FROM DATA_TEMP) S
ON (D.SELLER_ACCOUNT_ID = S.ACCOUNT_ID
AND (D.CATEGORY_ID, 'dummy') = ((S.CATEGORY_ID_OLD, 'dummy')))
WHEN MATCHED THEN UPDATE SET D.CATEGORY_ID = S.CATEGORY_ID_NEW;

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;

update rows from joined tables in oracle

I'm trying to migrate some tables into an existing table, I need to perform the updates only where DET_ATTACHMENT_ID equals DET_ATTACHMENT.ID, here's the query I have so far.
UPDATE DET_ATTACHMENT
SET attachment_type = 'LAB', -- being added by the query, to replace the table difference
payer_criteria_id = (
SELECT PAYER_CRITERIA_ID
FROM DET_LAB_ATTACHMENT
WHERE DET_LAB_ATTACHMENT.DET_ATTACHMENT_ID = DET_ATTACHMENT.ID)
WHERE exists(
SELECT DET_ATTACHMENT_ID
FROM DET_ATTACHMENT
JOIN DET_LAB_ATTACHMENT ON (ID = DET_ATTACHMENT_ID)
WHERE DET_ATTACHMENT_ID = DET_ATTACHMENT.ID
the problem with the existing query is that it's setting every row to have an attachment_type of "LAB", and nulling out the payer_criteria_id where it didn't match. What am I doing wrong?
The problem might be that your exists(...) predicate always evaluates to true, thus making the update run for all rows of det_attachment. Try it this way:
UPDATE DET_ATTACHMENT X
SET X.attachment_type = 'LAB',
X.payer_criteria_id = (
SELECT C.PAYER_CRITERIA_ID
FROM DET_LAB_ATTACHMENT C
WHERE C.DET_ATTACHMENT_ID = X.ID
)
WHERE
exists(
SELECT 1
FROM DET_ATTACHMENT A
JOIN DET_LAB_ATTACHMENT B
ON B.DET_ATTACHMENT_ID = A.ID
where B.det_attachment_id = X.id
)
;