Oracle SQL : Updating a column with SUM query of another table - sql

I have two tables :
Table1 with 5 columns (col1, col2, col3, col4, val1) and Table2 with Table1 with 5 columns (col1, col2, col3, col4, val2).
1. The Table1.val1 doesn't contain any value.
2. For both Table1 and Table2, col1, col2, col3 and col4 are the same and they are the primary key.
What I would like to do, is to update the Table1.val1 with the sum(Table2.val2) when Table1.col1 = Table2.col1 and Table1.col2 = Table2.col2 and Table1.col3 = Table2.col3 and Table1.col4 = Table2.col4.
I did something like :
UPDATE Table1
SET val1 = (
select t_sommevbrute.sumvalbrute from (
Select col1,col2,col3,col4,SUM(val2) sumvalbrute
From Table2
Where col3 = 2014 And col2=51
GROUP BY col1, col2, col3, col4) t_sommevbrute
WHERE Table1.col1 = t_sommevbrute.col1
and Table1.col2 = t_sommevbrute.col2
and Table1.col3 = t_sommevbrute.col3
and Table1.col4 = t_sommevbrute.col4)
But related to this question: Oracle SQL: Update a table with data from another table , I should have WHERE EXISTS clause.
Any help please!!
Thanks.

You can do this in following way:-
With Use of Temp Table:-
First Create Temp Table:-
Create table temp1 as
Select col1,col2,col3,col4,SUM(val2) as sumvalbrute
From table2
Where col3 = 3 And col2=2
GROUP BY col1, col2, col3, col4;
And then use Temp table to update Main Table1:-
UPDATE table1 SET table1.val1 = (SELECT temp1.sumvalbrute
FROM temp1
WHERE Table1.col1 = temp1.Col1
AND Table1.col2 = temp1.Col2
AND Table1.col3 = temp1.Col3
AND Table1.col4 = temp1.Col4);
SQL Fiddle :- http://sqlfiddle.com/#!4/4864d/5
WithOt Use of Temp Table:-
UPDATE table1 SET table1.val1 = (SELECT temp1.sumvalbrute
FROM
(Select col1,col2,col3,col4,SUM(val2) as sumvalbrute
From table2
Where col3 = 3 And col2=2
GROUP BY col1, col2, col3, col4) temp1
WHERE Table1.col1 = temp1.Col1
AND Table1.col2 = temp1.Col2
AND Table1.col3 = temp1.Col3
AND Table1.col4 = temp1.Col4);
SQL Fiddle:- http://sqlfiddle.com/#!4/c9286/2

You can simplify your query greatly:
UPDATE Table1
SET val1 = (select SUM(val2)
from Table2 t
where Table1.col1 = t.col1 and
Table1.col2 = t.col2 and
Table1.col3 = t.col3 and
Table1.col4 = t.col4
)
Where col3 = 2014 And col2 = 51;
You could use where exists. The purpose is to prevent NULL values when there is no match. However, I think pulling the where clause outside probably solves this problem. I note that the where clause is using the same values as the correlation conditions.

You can try this:
UPDATE t1 SET t1.val1 = SUM(t2.val2)
FROM table1
INNER JOIN table2 t2 ON t2.col1 = t1.col1
and t2.col2 = t1.col2
and t2.col3 = t1.col3
and t2.col4 = t2.col4

This kind of update can be achieved ALSO using MERGE statement:
Merge into Table1 using ( select SUM(val2) as val2, t.col1, t.col2, t.col3, t.col4
from Table2 t
group by t.col1, t.col2, t.col3, t.col4
) t -- This is the alias for table 2
on ( Table1.col1 = t.col1
and Table1.col2 = t.col2
and Table1.col3 = t.col3
and Table1.col4 = t.col4
)
when matched then
UPDATE Table1.val1 = t.val2 --HERE IS YOUR **UPDATE**
where Table1.col3 = 2004
and Table1.col2 = 51
;
commit;
Please don't forget to ADD ALIASES to the tables, and a good COMMIT after this code
This solution avoid you from create temporary tables, and works pretty well
Best regards.

Related

Using a subquery for IN clause Oracle

I am having some trouble using a subquery for the IN clause of a query.
Hard-coding the IN .. values allows the query to execute quickly, but using a subquery slows everything down. Is there a way to speed this query up?
SELECT col1, col2, col3 FROM table1
WHERE ...
and col1 in (SELECT col1 FROM table2)
...
*The values for the IN clause will be a list of strings
SELECT col1, col2, col3 FROM table1
WHERE ...
and col1 in ('str1', 'str2', 'str3', ...)
...
The above works fine.
EDIT:
I think I was oversimplifying the problem. The query I am trying to execute looks like this:
SELECT col1, col2, col3, ...
FROM table1 t1, table2 t2
WHERE t1.col1 IN (SELECT col FROM table3)
and t1.col2 < 50
and t2.col3 = t1.col3
...
You cant write select * from . If you give select * from, it doesnot understand which column to compare with from table2. Use the column name you need.
SELECT * FROM table1
WHERE ...
and col1 in (SELECT col1 FROM table2)
...
Use JOIN instead,
and keep an index defined on table1.col1 or table2.col3 or table1.col3 or table3.col :
SELECT col1, col2, col3, ...
FROM table1 t1
INNER JOIN table2 t2 on ( t2.col3 = t1.col3 )
INNER JOIN table3 t3 on ( t1.col1 = t3.col )
WHERE t1.col2 < 50;
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax. You should write the query as:
SELECT col1, col2, col3, ...
FROM table1 t1 JOIN
table2 t2
ON t2.col3 = t1.col3
WHERE t1.col1 IN (SELECT col FROM table3) AND
t1.col2 < 50;
I would write this using EXISTS, rather than IN:
SELECT col1, col2, col3, ...
FROM table1 t1 JOIN
table2 t2
ON t2.col3 = t1.col3
WHERE EXISTS (SELECT 1 FROM table3 t3 WHERE t1.col1 = t3.col) AND
t1.col2 < 50;
The filtering is all on table1; however, the columns are being compared with inequalities. I would try the following indexes: table2(col3), table1(col2, col1), and table3(col).

Deleting Semi Duplicate Rows in ORACLE SQL

I have rows in my table that needs deleting based on a few columns being duplicates.
e.g Col1,Col2,Col3,Col4
If Col1,Col2 and Col3 are duplicates regardless of what value is in Col4 I want both these duplicates deleted. How do I do this?
You can do this using the where clause:
delete from t
where (col1, col2, col3) in (select col1, col2, col3
from t
group by col1, col2, col3
having count(*) > 1
);
Group by these IDs and check with HAVING whether there are duplicates. With the duplicates thus found delete the records.
delete from mytable
where (col1,col2,col3) in
(
select col1,col2,col3
from mytable
group by col1,col2,col3
having count(*) > 1
);
Use EXISTS to remove a row if another row with same col1, col2 and col3 exists with a lower col4 value. I.e keep one col1, col2, col3 row.
delete from tablename t1
where exists (select 1 from tablename t2
where t2.col1 = t1.col1
and t2.col2 = t1.col2
and t2.col3 = t1.col3
and t2.col4 < t1.col4)
To remove both/all rows, skip the col4 condition, do a group by instead:
delete from tablename t1
where exists (select 1 from tablename t2
where t2.col1 = t1.col1
and t2.col2 = t1.col2
and t2.col3 = t1.col3
group by t2.col1, t2.col2, t2.col3
having count(*) > 1)

Differences between two tables

Data is like so, (table1 links up to table2) on table1.col2 = table2.col2
Based on that criteria,
Employee 5 below assigned to Area 1 in first table, however in second table that employee is not assigned to Area 1, so the result that would return would only be the first record of the first table (emp5, a1)
Example below
Table1
Col1 Col2
-------------
emp5 A1
emp6 A1
emp5 A2
Table2
Col1 Col2
--------------
emp7 A1
emp6 A1
emp5 A2
You can use MINUS, it is more intuitive. The syntax can be different in SQL Server, MySQL or Oracle, like you can see http://blog.sqlauthority.com/2008/08/07/sql-server-except-clause-in-sql-server-is-similar-to-minus-clause-in-oracle/
But I like MINUS, for instance
select
t1.Col1,
t1.Col2
from table1 t1
MINUS
select
t2.Col1,
t2.Col2
from table2 t2
This way, you can think like sets (math)!
This is tricky. You need employees who are in both tables. Then you need to check that col2 is different on one of the rows.
The following does this comparison using union all:
select col1, col2, max(which)
from ((select col1, col2, 1 as which
from table1 t1
where exists (select 1 from table2 t2 where t2.col1 = t1.col1)
) union all
(select col1, col2, 2 as which
from table2 t2
where exists (select 1 from table1 t1 where t2.col1 = t1.col1)
)
) tt
group by col1, col2
having count(*) = 1
This will also tell you which table has the extra row.
select table1.*
from table1
left join table2
on table1.col1 = table2.col1
and table1.col2 = table2.col2
where table2.col1 is null
if you only want those from table 1 that are also assigned to another project then
select distinct table1.*
from table1
join table2 as t2not
on t2not.col1 = table1.col1
and t2not.col2 <> table1.col2
left join table2
on table1.col1 = table2.col1
and table1.col2 = table2.col2
where table2.col1 is null

Updating more than 1 db column in an UPDATE SET statement using psycopg2

I try to update one table based on values found in another table. The following works:
UPDATE table1 SET col1 = ( SELECT col1 from table2 WHERE table2.col1 = table1.col1 );
I want to do the same using several columns. I thought the following should bring the desired result"
UPDATE table1 SET (col1, col2) = ( SELECT col1, col2 from table2 WHERE table2.col1 = table1.col1 );
but I get a
syntax error at or near "SELECT"
LINE 1: UPDATE table1 SET (col1, col2) = ( SELECT col1, col2 f...
Any help appreciated.
This should work:
update table1 t1
set col1 = t2.col1,
col2 = t2.col2
from table2 t2
where t1.col1 = t2.col1;
SQL Fiddle Demo
With that said, no need to update col1 = t2.col1 since that is your join criteria.

Update multiple columns in SQL with bound multi-part identifier

I'm trying to update multiple columns in a MS SQL statement using a sub-query. A search led me to something like:
UPDATE table1
SET col1 = a.col1, col2 = a.col2, col3 = a.col3 FROM
(SELECT col1, col2, col3 from table2 where <expression>) AS a
WHERE table1.col1 <expression>
Link
My problem is that in the inner WHERE expression I need a reference to a specific field in table1:
UPDATE table1
SET col1 = a.col1, col2 = a.col2, col3 = a.col3 FROM
(SELECT col1, col2, col3 from table2 where table1.col0 = table2.col0) AS a
WHERE table1.col1 <expression>
When I run that query I get "The multi-part identifier "table1.col0" could not be bound.
". Apparently when using that syntax SQL cannot bind the current table1 record in the subquery. Right now I am repeating the subquery for each field and using the syntax:
UPDATE table1
SET col1 = (subquery), col2 = (subquery)...
But that executes the subquery (which is very expensive) once per column, which I would like to avoid.
Any ideas?
in sql server, you can use a from clause in an update query. Join the tables as you would in a select. The table you are updating must be included in the joins.
update table_1
set field_1 = table_2.value_1
from table_1
inner join table_2
on (table_1.id = table_2.id)
Or if you dislike the join syntax this will also work:
UPDATE table1
SET col1 = a.col1, col2 = a.col2, col3 = a.col3
FROM table1, table2 as a
WHERE table1.col0 = a.col0
AND table1.col1 <expression>
Your car use CROSS APPLY command to update multiple columns from sub select
UPDATE t1
SET t1.col1 = a.col1, t1.col2 = a.col2, t1.col3 = a.col3
FROM table1 t1
CROSS APPLY
(SELECT col1, col2, col3 from table2 where table1.col0 = table2.col0) a(col1,col2,col3)