Update table efficiently in Oracle - sql

I have 3 tables A(a1, a2) , B (b1, b2), C (c1, c2). I want to perform update in the following way:
UPDATE A
SET A.a2 = (SELECT 2* SUM(C.c2)
FROM B JOIN C
ON B.b1 = C.c1 WHERE A.a1 = B.b2)
WHERE A.a1 = (SELECT B.b2
FROM B JOIN C
ON B.b1 = C.c1 HAVING SUM(C.c2) > 1000);
The problem with this approach is the tables B and C need to be joined multiple times.
Is there any good solution to solve this problem?
I tried:
UPDATE A SET A.a2 = (SELECT CASE
WHEN SUM(C.c2) > 1000 THEN 2*SUM(C.c2)
ELSE A.a2
END
FROM B JOIN C
ON B.b1 = C.c1
WHERE A.a1 = B.b2);
but it does not use the index on a1 and also it will update all rows in table A which is even slower than the original one

This kind of update is typically faster when done with a MERGE instead:
MERGE INTO a
using
(
SELECT b.b2, 2 * SUM(C.c2) as c2_sum
FROM B
JOIN C ON B.b1 = C.c1
group by b.b2
HAVING SUM(C.c2) > 1000
) t on (t.b2 = a.a1)
when matched then update
set a2 = t.c2_sum;

If its really long operation you may create intermediate table where you calculate result. But you need to have primary key on both tables
Create table int_a as
SELECT 2* SUM(C.c2) as new_a2
, B.b2
FROM B JOIN C
ON B.b1 = C.c1 WHERE A.a1 = B.b2
GROUP BY B.b2
HAVING SUM(C.c2) > 1000
alter table int_a add constraint primary key pk_int_a (b2);
alter table a add constraint primary key pk_a (a2);
and update table a with join
update (select a2, int_a.new_a2
from A, INT_A
where A.a1 = INT_A.b2)
set a2 = new_a2

You can use "with clause"
update A
SET A.a2 =
((with data as (SELECT B.b2, C.c2 FROM B JOIN C ON B.b1 = C.c1)
select *
from data_b_c)
select * from data b_c, A where A.a1 = b_c.b2 HAVING SUM(b_c.c2) > 1000)

Related

Update values from one table in another

I have tables A,B and C. I need to select certain values from all rows in Table A and then for every row in A, I need to update values in Table B and Table C.
Pseudo Code would look like this:
SELECT A1, A2, A3, A4 FROM Table A
UPDATE Table B SET B2=A2, B3=A3, B4=A4 WHERE B1 = A1;
UPDATE Table C SET C2=A2, C3=A3, C4=A4 WHERE C1 = A1;
How can I achieve this?
In Oracle, you would use two update statements:
update b
set (b2, b3, b4) = (select a2, a3, a4 from a where a.a1 = b.b1);
update c
set (c2, c3, c4) = (select a2, a3, a4 from a where a.a1 = c.b1);
You need two update statements. You could use an inline view:
update (
select a.a2, a.a3, a.a4 , b.b2, b.b3, b.b4
from a
inner join b on b.b1 = a.a1
) u
set u.b2 = u.a2, u.b3 = u.a3, u.b4 = u.a4
The upside is that this only updates matching rows - while, using the correlated subquery technique, you need to repeat the subquery in the where clause.
Another neat syntax that does what you want in Oracle is merge:
merge into b
using a on (a.a1 = b.a1)
when matched then update set b.b2 = a.a2, b.b3 = a.a3, b.b4 = a.a4;

Choosing MAX values by the "where=" statement

Suppose, i have table A with columns a1, a2 and B table with b1, b2.
I need to join them like this
proc sql;
create C as
select a1, b1
from A as t1
left join B( where=(b1=max(select b1 from B)) as t2
on t1.a2 = t2.b2
run;
The problem is in where=(a1=max(select a1 from A)). It doesn't work somewhy. I need a where= solution, because B is big and where= is really fast
Your condition is on the first table. Hence, in a left join, such a condition usually goes in the where clause. Conditions on the second table would go in the on clause.
One method of doing what you want is to use a subquery:
proc sql;
create C as
select a1, b1
from A t1 left join
B t2
on t1.a2 = t2.b2
where t1.a1 = (select max(tt1.a1) from A tt1)
run;
It seems you only got the syntax wrong. This gets you the B record where b2 matches a2 and b1 is the maximum b1 value in the table.
create table c as
select a.a1, b.b1
from a
left join b on b.b2 = a.a2
and b.b1 = (select max(b1) from b);
Or are you simply trying to get the maximum b1 from all B records where b2 matches a2? That would be:
create table c as
select a.a1, max(b.b1)
from a
left join b on b.b2 = a.a2
group by a.a1;

To use SQL join or not

I have a query with 2 tables Table A and Table B.
Table_A : A_ID, B_ID, A3, A4, A5
Table_B : B_ID, B2.
I want value of column A3 from Table_A and B2 from Table_B.
I tried this query:
select
b.B2, a.A3
from
Table_A a
join
Table_B b on (a.A_ID = b.B_ID)
The query returns nothing. What am I doing wrong?
It would seem that the B_ID column in Table A is the foreign key to Table B - in that case, you need to join on that column:
select
b.B2, a.A3
from
Table_A a
inner join
Table_B b on a.B_ID = b.B_ID
Use a.B_ID (not a.A_ID) to establish the join between the two tables.

Trouble with select statement on three table join

Im trying to write a query that will return a set of columns from three different tables.
The table that is link between the other two tables is called Table_A, it contains the keys of for the other two tables.
The second table is called the Table_B and the last table is called the Table_C.
Table_A columns.
| a_ID (primary key)| b_ID (foreign key)| c_ID
(foreign key)| ..... |
Table_B columns
|b_ID (primary key)| b1 | b2 | ...... |
Table_C columns
| c_ID (primary key) | c1 | c2 | ...... |
This is my SQL Query below. (Im only concerned with the columns above although there are more in each table.)
SELECT b.b_ID
, b.b1
, b.b2
, a.a_ID
, c.c1
, c.c2
FROM Table_A AS a
JOIN Table_B AS b ON a.b_ID = b.b_ID
JOIN Table_C AS c ON a.c_ID = c.c_ID
Im using open office for my projects and the error I'm getting is
"Table not found in statement [ SELECT b.b_ID
, b.b1
, b.b2
, a.a_ID
, c.c1
, c.c2
FROM Table_A AS a
JOIN Table_B AS b ON a.b_ID = b.b_ID
JOIN Table_C AS c ON a.c_ID = c.c_ID]"
For some reason if I change the select statement just to get all columns (*) it returns the correct results but I need to narrow it down to the columns listed in my query.*
SELECT *
FROM Table_A AS a
JOIN Table_B AS b ON a.b_ID = b.b_ID
JOIN Table_C AS c ON a.c_ID = c.c_ID'
EDIT: I have removed the actual table and column names so that you don't have to understand the story to help with the issue.
Shouldn't your WHERE clause be:
WHERE b.eventStartDate > '2013-10-01'
?
This is a "spot the difference" type of question...

How to update with inner join in Oracle

Could someone please verify whether inner join is valid with UPDATE statment in PL SQL?
e.g.
Update table t
set t.value='value'
from tableb b inner join
on t.id=b.id
inner join tablec c on
c.id=b.id
inner join tabled d on
d.id=c.id
where d.key=1
This synthax won't work in Oracle SQL.
In Oracle you can update a join if the tables are "key-preserved", ie:
UPDATE (SELECT a.val_a, b.val_b
FROM table a
JOIN table b ON a.b_pk = b.b_pk)
SET val_a = val_b
Assuming that b_pk is the primary key of b, here the join is updateable because for each row of A there is at most one row from B, therefore the update is deterministic.
In your case since the updated value doesn't depend upon another table you could use a simple update with an EXIST condition, something like this:
UPDATE mytable t
SET t.VALUE = 'value'
WHERE EXISTS
(SELECT NULL
FROM tableb b
INNER JOIN tablec c ON c.id = b.id
INNER JOIN tabled d ON d.id = c.id
WHERE t.id = b.id
AND d.key = 1)
update t T
set T.value = 'value'
where T.id in (select id from t T2, b B, c C, d D
where T2.id=B.id and B.id=C.id and C.id=D.id and D.key=1)
-- t is the table name, T is the variable used to reffer to this table