MERGE vs. UPDATE - sql

I was trying to look for it online but couldn't find anything that will settle my doubts.
I want to figure out which one is better to use, when and why?
I know MERGE is usually used for an upsert, but there are some cases that a normal update with with subquery has to select twice from the table(one from a where clause).
E.G.:
MERGE INTO TableA s
USING (SELECT sd.dwh_key,sd.serial_number from TableA#to_devstg sd
where sd.dwh_key = s.dwh_key and sd.serial_number <> s.serial_number) t
ON(s.dwh_key = t.dwh_key)
WHEN MATCHED UPDATE SET s.serial_number = t.serial_number
In my case, i have to update a table with about 200mil records in one enviorment, based on the same table from another enviorment where change has happen on serial_number field. As you can see, it select onces from this huge table.
On the other hand, I can use an UPDATE STATEMENT like this:
UPDATE TableA s
SET s.serial_number = (SELECT t.serial_number
FROM TableA#to_Other t
WHERE t.dwh_serial_key = s.dwh_serial_key)
WHERE EXISTS (SELECT 1
FROM TableA#To_Other t
WHERE t.dwh_serial_key = s.dwh_serial_key
AND t.serial_number <> s.serial_number)
As you can see, this select from the huge table twice now. So, my question is, what is better? why?.. which cases one will be better than the other..
Thanks in advance.

I would first try to load all necessary data from remote DB to the temporary table and then work with that temporary table.
create global temporary table tmp_stage (
dwh_key <your_dwh_key_type#to_devstg>,
serial_number <your_serial_number_type##to_devstg>
) on commit preserve rows;
insert into tmp_stage
select dwh_key, serial_number
from TableA#to_devstg sd
where sd.dwh_key = s.dwh_key;
/* index (PK on dwh_key) your temporary table if necessary ...*/
update (select
src.dwh_key src_key,
tgt.dwh_key tgt_key,
src.serial_number src_serial_number,
tgt.serial_number tgt_serial_number
from tmp_stage src
join TableA tgt
on src.dwh_key = tgt.dwh_key
)
set src_serial_number = tgt_serial_number;

Related

How can I set and calculate a variable inside a merge statement

As title says, I was wondering how I can calculate and set a variable inside a merge statement. If that is even possible.
Example:
MERGE TABLE_1 as target
USING TABLE_2 as source
ON (target.USER_ID = source.USER_ID)
WHEN NOT MATCHED THEN
INSERT (
USER_ID,
CURRENT_CALCULATION,
CURRENT_CALCULATION_VALUE )
VALUES (
source.USER_ID,
SET #CURRENT_CALCULATION = (select value from table3 where table3.USER_ID = source.USER_ID),
... REUSE #CURRENT_CALCULATION for other purposes ...
);
I have tried different kind of syntax but none seems to work.
I don't believe this is possible. Without a little more detail I can't be sure that this will work for your situation, but how about simply carrying out this logic before your MERGE statement? You could always dump everything into a temp table at the point you do all the calculations if what you're trying to avoid is hitting the same tables twice.
If you did that, you could simply use your temp table as the source for the merge - you may not even need to put it into a variable, as you might be able to include it as a column of the temp table.
Move the logic to source part of Merge and reuse it
MERGE TABLE_1 AS target
USING (SELECT t2.*,
t3.value
FROM TABLE_2 t2
LEFT JOIN table3 t3
ON t3.USER_ID = t2.USER_ID) AS source
ON ( target.USER_ID = source.USER_ID )
WHEN NOT MATCHED THEN
INSERT ( USER_ID,
CURRENT_CALCULATION,
CURRENT_CALCULATION_VALUE )
VALUES ( source.USER_ID,
source.value,
source.value + some logic );
Considering there is 1:1 relationship between table 2 and table 3 based on your correlated sub-query used to find #CURRENT_CALCULATION

Oracle : How to update multiple columns from different table?

I am using oracle database and have a situations to update fields from some other tables. My issue is it is updating all the records instead of specified conditions.
For example, I am trying to update perm_address and temp_address in EMPLOYEE table from ADDRESS table. Right now, I am using below query. But, it is updating all the records.
UPDATE EMPLOYEE EMP
SET (EMP.PERM_ADDRESS, EMP.TEMP_ADDRESS) =
(SELECT ADDR.PERM_ADDR,ADDR.TEMP_ADDR
FROM ADDRESS ADDR
WHERE ADDR.ID=EMP.ADDRESS_ID
);
In Oracle how to handle this situations? Normally, how to handle the update from multiple table into source table?
Thanks in advance....
Add a WHERE clause to update only matching records:
UPDATE EMPLOYEE EMP
SET (EMP.PERM_ADDRESS, EMP.TEMP_ADDRESS) =
(SELECT ADDR.PERM_ADDR, ADDR.TEMP_ADDR
FROM ADDRESS ADDR
WHERE ADDR.ID = EMP.ADDRESS_ID
)
WHERE EXISTS (SELECT 1 FROM ADDRESS ADDR WHERE ADDR.ID = EMP.ADDRESS_ID);
Updating a table with data from another table is often simpler using the MERGE statement. https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016.htm
Something like this:
merge into employee emp
using address addr
on (addr.id = emp.address_id)
when matched
then update
set emp.perm_address = addr.perm_addr,
emp.temp_address = addr.temp_addr;
updating one table by another table - the basic format is
--ORACLE
update tableX t set (t.fldA, t.fldB) =
(select fldA, fldB from table_B where ID ='X')
where t.ID = 'Y'

Compare Temp table and Main table to find matches

I have two tables #mtss table:
#mtss
( [MM],[YYYY],[month_Start],[month_Finish],[ProjectID],[ProjectedBillable],[ProjectedPayable],[ActualBilled],[ActualPaid],[Total_To_Bill],[Total_To_Pay])
tbl_Snapshot ([MM],[YYYY],[month_Start],[month_Finish],[ProjectID],[ProjectedBillable],[ProjectedPayable],[ActualBilled],[ActualPaid],[Total_To_Bill],[Total_To_Pay]
)
I need to compare two tables and find matches
if tbl_snapshot [MM] and [ProjectId] matches then delete record in tbl_snapshot and insert record from #mtts.
Thanks in advance.
Since you're on 2008, you can use MERGE to perform the as a single logical operation:
;merge into tbl_Snapshot s
using #mtss m on s.MM = m.MM and s.ProjectId = m.ProjectId
when matched then update
set
YYYY = m.YYYY,
month_Start = m.month_Start
/* Other columns as well, not going to type them all out */
;
This would also easily extend to other cases you may have to deal with, if the data only exists in one table and not the other, with addition match clauses.
Of course, thinking further, in this case a simple UPDATE would work also. A DELETE followed by an INSERT (where the deleted and inserted rows are related by a key) is the equivalent of an UPDATE.
Somethig like:
DELETE tbl_snapshot
FROM tbl_snapshot ss
INNER JOIN #mtss m ON m.MM = ss.MM AND m.ProjectId = ss.ProjectId
(I wrote the code directly to this editor so it might have errors, but it should give you an idea how to continue)

How to update table based on row index?

I made a copy of an existing table like this:
select * into table_copy from table
Since then I've made some schema changes to table (added/removed columns, changed order of columns etc). Now I need to run an update statement to populate a new column I added like this:
update t
set t.SomeNewColumn = copy.SomeOldColumn
from t
However, how do I get the second table in here based on row index instead of some column value matching up?
Note: Both tables still have equal number of rows in their original positions.
You cannot join the tables without a key to define each row uniquely, the position of the data in the table has no bearing on the situation.
If you tables do not have a primary key you need to define one.
If you have an ID on it, you can do this:
update t set
t.SomeNewColumn = copy.SomeOldColumn
from
table t
inner join table_copy copy on
t.id = copy.id
If you have no way to uniquely identify the row and are relying on the order of the rows, you're out of luck, as row order is not reliable in any version of SQL Server (nor most other RDBMSes).
You could use this to update them by matching ids
UPDATE
t
SET
t.SomeNewColumn = other_table.SomeOldColumn,
FROM
original_table t
INNER JOIN
other_table copy
ON
t.id = copy.id
or if you don't have the ids you might be able to pull out something by using ROW_NUMBER function to enumerate the records, but that's a long shot(I haven't checked if it's possible).
If you're updating, you'll need a primary key to join on. Usually in that case, the others' answers will suffice. If for some reason you still need to update the table with a resultset in a certain order, you can do this:
UPDATE t SET t.SomeNewColumn = copy.SomeOldColumn
FROM table t
JOIN (SELECT ROW_NUMBER() OVER(ORDER BY id) AS row, id, SomeNewColumn FROM table) t2
ON t2.Id = t.Id
JOIN (SELECT ROW_NUMBER() OVER(ORDER BY id) AS row, SomeOldColumn FROM copytable) copy
ON copy.row = t2.row
You get the new table and its row numbers in the order you want, join the old table and its row numbers in the order you want, and join back to the new table so the query has something to directly update.

Multiple Query Writing in Single Query

I have two tables in Database , I need to select a field from one table and update it in another table with a condition where id is same .. Is it Possible to write in single query ???
This should work for you:
update storage
set storage.email = (select register.email
from register
where register.id = storage.id)
Yeah it is, you could do this for example:
UPDATE Origin SET DesiredColumn = NewValue
FROM Origin
JOIN NewTable ON Origin.Id = NewTable.Id
And guess the column names were like DesiredColumn in the updating table and NewValue in the table that holds the new value.
Yes, this is possible, although the syntax depends on the type of SQL you are using.
Here is an example for T-SQL (for Microsoft SQL Server)
UPDATE
S
SET
Email = R.Email
FROM
dbo.Register R
INNER JOIN dbo.Storage S
ON S.RegisterID = R.RegisterID