Oracle SQL correlated update low performance - sql

I have to update table(table3) with data from two other tables.
These two tables (table1,table2) are both describing single object, therefore table1.id equals table2.id for that single object.
Table 3 is a many-to-many mapping table for that object and another one which is not important here. Into that mapping table I need to put some data from table1 and table2.
I am trying to update table3 with correlated query, but it takes a very long time to complete. I ran this query on group of ~500.000 records and it runs for over an hour now.
Am I doing something wrong here?
UPDATE table3 t3
SET (t3.some_value1, t3.other_value1, t3.some_value2, t3.other_value2) =
( SELECT t1.some_value1, t1.other_value1, t2.some_value2, t2.other_value2
FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id
WHERE t3.fk = t1.id)
WHERE EXISTS (SELECT 1 FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id WHERE t3.fk = t1.id);
SELECT * FROM table3;
SQL Fiddle

Use this:
UPDATE
(SELECT
T3.SOME_VALUE1 TARGET1,
T3.OTHER_VALUE1 TARGET2,
T3.SOME_VALUE2 TARGET3,
T3.OTHER_VALUE2 TARGET4,
T1.SOME_VALUE1 SOURCE1,
T1.OTHER_VALUE1 SOURCE2,
T2.SOME_VALUE2 SOURCE3,
T2.OTHER_VALUE2 SOURCE4
FROM
TABLE1 T1
JOIN TABLE2 T2
ON T1.ID = T2.ID
JOIN T3
ON T3.FK = T1.ID)
SET
TARGET1 = SOURCE1,
TARGET2 = SOURCE2,
TARGET3 = SOURCE3,
TARGET4 = SOURCE4;
If you face ORA-01779 cannot modify a column which maps to a non key-preserved table then try using UPDATE /*+ BYPASS_UJCV */ or add a unique index on T1.ID, T2.ID, T3.FK

The answer provided by #SriniV uses a technique called an Updatable Join View. In later versions of Oracle, this can be replaced with a MERGE:
MERGE INTO t3
USING (
SELECT t1.id
t1.some_value1,
t1.other_value1,
t2.some_value2,
t2.other_value2
FROM table1 t1
JOIN table2 t2 ON t1.id = t2.id
WHERE 1=1
AND t3.fk = t1.id
) a ON (
t3.fk = a.id
)
WHEN MATCHED THEN UPDATE
SET t3.some_value = a.some_value,
t3.other_value1 = a.other_value1
t3.some_value2 = a.some_value2
t3.other_value2 = a.other_value2

Related

How do I look for non-matching values across 3 SQL tables?

I'm looking to do what I believe is a double-nested check across three tables, but have no idea how to do so.
I have Table1, Table2, and Table3.
All are tied by an ID and a "Longform" and "Shortform" in Table1:
I'm trying to find:
Entries whose IDs appear in Table2 that have the same Longform as those in Table3, but don't share the same Shortform.
This is about as far as I've gotten:
SELECT T2.Longform,T2.Shortform FROM(
SELECT Table1.Longform,Table1.Shortform,Table1.ID FROM OuterTable1.Table1
LEFT JOIN OuterTable2.Table2 on Table1.ID = Table2.ID)
WHERE Table2.ID IS NOT NULL) T2
;
I know I'm probably going to have to do another nested select, or a join, on Outertable3.Table3 but I'm not sure which... Or where...
Any help appreciated as always.
Try the following:
Select *
(
Select T1.*
from T2
inner join T1
on T1.ID = T2.ID
) as Tab
inner join
(
Select T1.*
from T3
inner join T1
on T1.ID = T3.ID
) as Tab2
on Tab.id = Tab2.id
and Tab.Longform = Tab2.Longform
and Tab.Shortform <> Tab2.Shortform
To get the longform join table1 to table2 or table3. Then use EXISTS to check in a subquery if the IDs of table1 are different but the longform is equal.
SELECT *
FROM table2 t21
INNER JOIN table1 t11
ON t11.id = t21.id
WHERE EXISTS (SELECT *
FROM table3 t32
INNER JOIN table1 t12
ON t12.id = t32.id
WHERE t12.id <> t11.id
AND t12.longform = t11.longform);
Assuming ID is unique in all three tables
Select t2.id,t2.shortform, t1.shortform AS shortformTab1, t2.longform
FROM table2 t2
JOIN table3 t3
ON t2.id = t3.id AND t2.longform = t3.longform
JOIN table1 t1
ON t2.id = t1.id AND t2.shortform != t1.shortform

Update values in one table with values in another table

I have table1 and table2. They have the same columns and the column ID is the one that i can use to connect the tables.
How can i run foreach statment that will update row Name in table1 with the value for column Name in table2?
I need this so i can fix the column Name in Table1 because it is incorect , and the good values for it are in table2
I tried using a single update statement but it takes forever to execute because both tables are with over 600 000 rows
update
table1 t1
set
(
t1.name
) = (
select
t2.name
from
table2 t2
where
t2.id = t1.id
and
rownum = 1
)
where exists (
select
null
from
table2 t2
where
t2.id = t1.id
);
For this query:
update table1 t1
set t1.name = (select t2.name from table2 t2 where t2.id = t1.id and rownum = 1)
where exists (select 1
from table2 t2
where t2.id = t1.id
);
You want an index on table2(id, name).
A simple inner join should work this.
UPDATE T1
SET T1.NAME = T2.NAME
FROM MyTable T1
INNER JOIN MyOtherTable T2
ON T1.ID = T2.ID

How can I update multiple rows in one query?

How can I update multiple rows in one query?
I have something like this:
update POL_VYMFOND set fk_vsoub='2245'
where fk_vsoub in (select HL_VYMSOUB.ID_VSOUB
from POL_VYMSEZN
inner join HL_VYMSEZN
on HL_VYMSEZN.ID_VSEZN=POL_VYMSEZN.FK_VSEZN
inner join HL_VYMSOUB
on HL_VYMSOUB.FK_VSEZN=HL_VYMSEZN.ID_VSEZN
where POL_VYMSEZN.FK_BUDOVA='4')
but definitely wrong.
Is it possible to do this?
I would like to change column values in one table according to values from another table.
Thank you
Generic answer for future developers.
SQL Server
UPDATE
t1
SET
t1.column = t2.column
FROM
Table1 t1
INNER JOIN Table2 t2
ON t1.id = t2.id;
Oracle (and SQL Server)
UPDATE
t1
SET
t1.colmun = t2.column
FROM
Table1 t1,
Table2 t2
WHERE
t1.ID = t2.ID;
MySQL
UPDATE
Table1 t1,
Table2 t2
SET
t1.column = t2.column
WHERE
t1.ID = t2.ID;
Firebird 2.1
UPDATE dest_table t1
SET
field1 = (select field1 from src_table t2 where t2.pk = t1.pk),
field2 = (select field2 from src_table t2 where t2.pk = t1.pk)
WHERE EXISTS (select 1 from src_table t2 where t2.pk = t1.pk)
For other versions of Firebird please check this link
Hope this will help you, and will solve your issue.

SQL: select from t1 all rows for which there's no corresponding in t2

Let's say I have a table t1 with only one column: id, and I have a table t2 with two columns: id and Memo. I need to select those id from t1, for which there is NO row in t2 that satisfies both of the following two conditions t1.id = t2.id and t2.Memo = 'myText'. How can I do that? I have tried using join, but that selects row that do satisfy some conditions, whereas I need the opposite.
SELECT *
FROM t1
WHERE NOT EXISTS (SELECT 1
FROM t2
WHERE t2.id = t1.id
AND t2.Memo = 'myText')
One way to do it is using LEFT JOIN:
select id
from t1
left join t2
on t1.id = t2.id and t2.Memo = 'myText'
where t2.id is null
I'm not good in understanding your question:
You mean those t1.id EXISTS in t2 BUT the corresponding t2.Memo <> 'myText'?
SELECT t1.id FROM t1 JOIN t2
ON t1.id = t2.id
HAVING t1.id NOT IN (SELECT id FROM t2 WHERE Memo = 'myText');
Or all t1.id either NOT EXISTS in t2 or EXISTS but Memo <> 'myText'?
SELECT id FROM t1 WHERE id NOT IN (SELECT id FROM t2 WHERE Memo = 'myText');

sql oracle update

I have this SQL...
UPDATE table1 t1
SET (t1.wert) =
(select t2.bezeichnung from table2 t2
where t1.id = t2.cpbezeichnung)
where t1.id = t2.cpbezeichnung
... which I cant run because it says me that it doesnt know t2.cpbezeichnung in line #5.
How can I fix it?
Table with alias t2 is not defined for UPDATE query, so it's clearly not known at line 5. Table t2 is defined only inside subquery on lines 3 and 4.
What exactly are you trying to achieve with condition on line 5?
If do you want prevent setting NULL into t1.wert for rows where there is no appropriate record in table t2, then you need to replace condition on line 5
UPDATE table1 t1
SET (t1.wert) =
(select t2.bezeichnung from table2 t2 where t1.id = t2.cpbezeichnung)
where t1.id IN (SELECT t2.cpbezeichnung from table2)
This will set values in t1.wert only for records where t1.id exists in t2.cpbezeichnung.
The t2 alias (along with table2) is only visible in the subquery. My guess is that you want
UPDATE table1 t1
SET t1.wert = (select t2.bezeichnung
from table2 t2
where t1.id = t2.cpbezeichnung)
where exists (select 1
from table2 t2
where t1.id = t2.cpbezeichnung)
which updates every row where there is a match between the two tables. If that's not what you want, posting a test case would be helpful.
When using correlated subqueries you cannot use an alias from the inner query in the outer query.
The outer query knows nothing about the inner query except its results.
Ref
You will have to use a Inner join on the two tables.
Something like
UPDATE table1 t1 INNERJOIN table t2 ON your_table_condition SET t1.wert = (select t2.bezeichnung from t2 where t1.id = t2.cpbezeichnung) where t1.id = t2.cpbezeichnung