Update values from one table in another - sql

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;

Related

How to update Table 1 from multiple other tables when they have nothing in common?

I have a main table and 3 other tables. Each of these tables has a single row only. I would like to update columns of TableMain with corresponding columns from other tables. And these tables don't have any columns that I can join.
create table TableMain(a1 int, a2 int, b1 int, b2 int, c1 int, c2 int)
create table TableA(a1 int, a2 int)
create table TableB(b1 int, b2 int)
create table TableC(c1 int, c2 int)
I have the following, which works, but looks horrible:
update TableMain
set a1 = (select a1 from TableA),
a2 = (select a2 from TableA),
b1 = (select b1 from TableB),
b2 = (select b2 from TableB),
c1 = (select c1 from TableC),
c2 = (select c2 from TableC)
I've tried the code below but I am getting NULLs, so this approach doesn't work:
update TableMain
set a1 = ta.a1, a2 = ta.a2,
b1 = tb.b1, b2 = tb.b2,
c1 = tc.c1, c2 = tc.c2,
from TableA ta, TableB tb, TableC tc
Is there a more elegant way to update these columns?
P.S. I asked a similar question, but it addressed updating from a single table.
Consider:
UPDATE tm
SET tm.a1 = ta.a1,
tm.a2 = ta.a2,
tm.b1 = tb.b1,
tm.b2 = tb.b2,
tm.c1 = tc.c1,
tm.c2 = tc.c2
FROM TableMain tm
CROSS JOIN TableA ta
CROSS JOIN TableB tb
CROSS JOIN TableC tc

Using AND in an INNER JOIN

I am fairly new with SQL would like to understand the logic below.
SELECT *
FROM Table A A1
INNER JOIN TABLE B B1 ON B1.ID = A1.ID AND A1 = 'TASK';
Not sure if this is a clear detail but please let me know. Thanks!
SELECT *
FROM Table A A1
INNER JOIN TABLE B B1 ON B1.ID = A1.ID AND A1.Column = 'TASK'
is the same as
SELECT *
FROM Table A A1
INNER JOIN TABLE B B1 ON B1.ID = A1.ID
WHERE A1.Column = 'TASK'
It's even the same performance wise, it's just a different way to write the query. In very large queries it can be more readable to use an AND directly on an INNER JOIN instead of "hiding" it the in the WHERE part.
This wouldn't run at all
SELECT *
FROM Table A A1 INNER JOIN
TABLE B B1
ON B1.ID = A1.ID AND A1 = 'TASK';
This will run because I added a column name (SomeColumn):
SELECT *
FROM Table A A1 INNER JOIN
TABLE B B1
ON B1.ID = A1.ID AND A1.SomeColumn = 'TASK';
And is the same as this
SELECT *
FROM Table A A1 INNER JOIN
TABLE B B1
ON B1.ID = A1.ID
WHERE A1.SomeCoumn = 'TASK';
Whenever you join to a constant it is pretty much the same as adding an additional criterion to the where clause. The only reason to put it up with the join is for code clarity.
SELECT * -- Select all the columns
FROM TABLE A A1 -- From the table A. A1 is like a nickname you are giving table A. Instead of typing A.ColumnName (A couldbe a very long name) you just type A1.ColumnName
INNER JOIN TABLE B B1 -- You are inner joining Table A and B. Again, B1 is just a nickname. Here is a good picture explaning joins.
ON B1.ID = A1.ID -- This is the column that the 2 tables have in common (the relationship column) These need to contain the same data.
AND A1 = 'TASK' -- This is saying you are joining where A1 tablename

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;

Update table efficiently in Oracle

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)

Update duplicate columns table with join

I am having a problem for Oracle update SQL with join. I have a table A which has 5 columns (C1, C2, C3, C4, C5); table B which has 3 columns (D1, D2, D3). For table A, I only use 2 columns (C2, C3) to join table B (D1, D2), and update table A column C2 with table B column D3.
For table A, it will be lots of duplicates for both C2 and C3; but for condition C4 as 10, there will be no duplicates which is what I want to update.
For example, table A has records as:
1,100,1500,10,'ORG'
1,200,2000,10,'ORG'
1,300,2500,10,'ORG'
2,1000,500,20,'PERSON'
2,1000,200,20,'PERSON'
2,2000,200,20,'PERSON'
You can see that for C4 as 10, there is no duplicate for C2 and C3. But for C4 as 20, there will be duplicates for C2 and C3.
For table B, it will be like
100,1500,80
200,2000,100
300,3000,200
There is no duplicates for table B, and will join B with A as A.C2 = B.D1 and A.C3 = B.D2 to update A.C2 to B.D3.
I only have to update C4=10 records to join with table B based on B.D1 and B.D2.
I have SQL as below, but failed as
ORA-01779: cannot modify a column
which maps to a non key-preserved
table
Can anyone tell me what is wrong with my SQL?
UPDATE (
SELECT A.C2 OID, B.D3 TID FROM A, B
WHERE A.C2 = B.D1 AND A.C3 = B.D2 AND A.C4=10 AND B.D3 <> ' ' )
SET OID = TID
Thanks a lot!
Can't you use an update statement like...
UPDATE A
set c2 = (select D3
from B
where B.D2 <> ' ' and
A.C2 = b.D1 and A.C3=B.D2)
)
where A.C4=10
Also, your question and the problem description itself looks like a puzzle thtis very hard to understand.
Can you post some data and create table statements so that it's easy to reproduce your case ?(from next time maybe....)
First, it sounds like you are trying to update TableA. Second, the official ANSI specification for the Update statement does not provide for a join directly in the statement (you can have joins only through subqueries). One reason is that it would create ambiguities when duplicate rows were involved. So, you might try something like:
Update A
Set OID = (
Select B.D3
From B
Where B.D1 = A.C2
And B.D2 = A.C3
And B.D3 Is Not Null
)
Where A.C4 = 10
And Exists (
Select 1
From B
Where B.D1 = A.C2
And B.D2 = A.C3
And B.D3 Is Not Null
)
UPDATE A
SET C2 = (
SELECT B.D3
FROM B
WHERE A.C2 = B.D1 AND A.C3 = B.D2)
WHERE A.C4=10
AND EXISTS (
SELECT *
FROM B2
WHERE A.C2 = B2.D1 AND A.C3 = B2.D2)
No need to alias for update statements. Also you have the condition on B.D2 <> ' ' and also A.C3 = B.D2, so it is just as easy to just filter on A.C3 <> ' ', since A is the target table. If A.C3 is never blank, then the condition is not even required.