Oracle SQL: Update a table with data from another table - sql

Table 1:
id name desc
-----------------------
1 a abc
2 b def
3 c adf
Table 2:
id name desc
-----------------------
1 x 123
2 y 345
In oracle SQL, how do I run an sql update query that can update Table 1 with Table 2's name and desc using the same id? So the end result I would get is
Table 1:
id name desc
-----------------------
1 x 123
2 y 345
3 c adf
Question is taken from update one table with data from another, but specifically for oracle SQL.

This is called a correlated update
UPDATE table1 t1
SET (name, desc) = (SELECT t2.name, t2.desc
FROM table2 t2
WHERE t1.id = t2.id)
WHERE EXISTS (
SELECT 1
FROM table2 t2
WHERE t1.id = t2.id )
Assuming the join results in a key-preserved view, you could also
UPDATE (SELECT t1.id,
t1.name name1,
t1.desc desc1,
t2.name name2,
t2.desc desc2
FROM table1 t1,
table2 t2
WHERE t1.id = t2.id)
SET name1 = name2,
desc1 = desc2

Try this:
MERGE INTO table1 t1
USING
(
-- For more complicated queries you can use WITH clause here
SELECT * FROM table2
)t2
ON(t1.id = t2.id)
WHEN MATCHED THEN UPDATE SET
t1.name = t2.name,
t1.desc = t2.desc;

try
UPDATE Table1 T1 SET
T1.name = (SELECT T2.name FROM Table2 T2 WHERE T2.id = T1.id),
T1.desc = (SELECT T2.desc FROM Table2 T2 WHERE T2.id = T1.id)
WHERE T1.id IN (SELECT T2.id FROM Table2 T2 WHERE T2.id = T1.id);

Update table set column = (select...)
never worked for me since set only expects 1 value - SQL Error: ORA-01427: single-row subquery returns more than one row.
here's the solution:
BEGIN
For i in (select id, name, desc from table1)
LOOP
Update table2 set name = i.name, desc = i.desc where id = i.id;
END LOOP;
END;
That's how exactly you run it on SQLDeveloper worksheet. They say it's slow but that's the only solution that worked for me on this case.

Here seems to be an even better answer with 'in' clause that allows for multiple keys for the join:
update fp_active set STATE='E',
LAST_DATE_MAJ = sysdate where (client,code) in (select (client,code) from fp_detail
where valid = 1) ...
The full example is here:
http://forums.devshed.com/oracle-development-96/how-to-update-from-two-tables-195893.html - from web archive since link was dead.
The beef is in having the columns that you want to use as the key in parentheses in the where clause before 'in' and have the select statement with the same column names in parentheses.
where (column1,column2) in ( select (column1,column2) from table where "the set I want" );

BEGIN
For i in (select id, name, desc from table2)
LOOP
Update table1 set name = i.name, desc = i.desc where id = i.id and (name is null or desc is null);
END LOOP;
END;

If your table t1 and it's backup t2 have many columns, here's a compact way to do it.
In addition, my related problem was that only some of the columns were modified and many rows had no edits to these columns, so I wanted to leave those alone - basically restore a subset of columns from a backup of the entire table. If you want to just restore all rows, skip the where clause.
Of course the simpler way would be to delete and insert as select, but in my case I needed a solution with just updates.
The trick is that when you do select * from a pair of tables with duplicate column names, the 2nd one will get named _1. So here's what I came up with:
update (
select * from t1 join t2 on t2.id = t1.id
where id in (
select id from (
select id, col1, col2, ... from t2
minus select id, col1, col2, ... from t1
)
)
) set col1=col1_1, col2=col2_1, ...

Related

Update row in a table based on multiple rows in another table

I have two tables: table1 and table2:
table1 has columns id and integer
table2 has columns id and boolean
table2 can have multiple rows with the same id
I want to update the integer column of table1 by looking at all rows with the same id in table2 and seeing if any of the boolean values are true. If so I want table1.integer to be 1, else I want it to be 0.
I have tried something like this:
UPDATE table1,
(
SELECT table2.id, Sum(table2.boolean) > 0
) AS 'condition'
from table2
WHERE 1
GROUP BY table2.id) table3
SET table1.integer =IF(table3.condition, 1, 0) where table1.id = table3.id
And it seems to work, but I wanted to ask if there is a nicer/cleaner/more succinct way of updating the rows of table1 according to multiple rows of table2.
I would recommend EXISTS:
UPDATE table1 t1
SET t1.integer = (EXISTS (SELECT 1
FROM table2 t2
WHERE t2.id = t.id AND
t2.boolean
)
);
This can take advantage of an index on table2(id, boolean). With such an index, it should be faster than an approach that uses JOIN and AGGREGATION.
The syntax of your query is MySql like, so you can do a join like this:
UPDATE table1 t1 INNER JOIN (
SELECT id, MAX(boolean) maxboolean
FROM table2
GROUP BY id
) t2 ON t2.id = t1.id
SET t1.integer = t2.maxboolean
If there are ids in table1 without a corresponding id in table2 and you want the integer column for them to be updated to 0 then use a LEFT join:
UPDATE table1 t1 LEFT JOIN (
SELECT id, MAX(boolean) maxboolean
FROM table2
GROUP BY id
) t2 ON t2.id = t1.id
SET t1.integer = COALESCE(t2.maxboolean, 0)

How to find difference in rows for two tables in DB2 or SQL Server

In the table1 I have 1421144 rows and table2 has 1421134 rows.
I tried this query, but I don't get any rows returned.
select table1.ID
from table1
where ID not in (select ID from table2)
I have also used this query:
select ID from table1
except
select ID from table2
But I don't get any rows. Please help me, if the table1 has duplicates how can I get those duplicates?
Assuming ids are unique, you can use full outer join in either database:
select coalesce(t1.id, t2.id) as id,
(case when t1.id is null then 'T2 only' else 'T1 only' end)
from t1 full outer join
t2
on t1.id = t2.id
where t1.id is null or t2.id is null;
It is quite possible that the two tables have the same sets of ids, but there are duplicates. Try this:
select t1.id, count(*)
from t1
group by t1.id
having count(*) > 1;
and
select t2.id, count(*)
from t2
group by t2.id
having count(*) > 1;
If you have duplicates, try:
WITH Dups AS(
SELECT ID, COUNT(ID) OVER (PARTITION BY ID) AS DupCount
FROM Table1)
SELECT *
FROM Dups
WHERE DupCount > 1;
If you need to delete the dups, you can use the following syntax:
WITH Dups AS(
SELECT ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID) AS DupCount
FROM Table1)
DELETE FROM Dups
WHERE DupCount > 1;
Obviously, however, check the data before you run a DELETE statement you got from a random on the internet. ;)
I Guess u have data type mismatch between 2 tables, cast them to integers and try your first query
select table1.ID from table1
where cast(ID as int) not in (select cast(ID as int) from table2)
If you have stored in a different format than int, cast them to varchar and
try with this datatype.
Not in takes longer to execute, use left join instead
select t1id from
(
select t1.id t1Id, t2.Id t2Id from table1 left join table2
on cast(t1.id as int) = cast(t2.id as int)
) x where t2Id is null

not in operator in SQL

there is 2 tables
table1
ID
1
2
4
6
7
TABLE2
2
4
6
i want those number from table1 which is not in table2 how i do this ?
i try this
select id from table1 t1
inner join table2 t2 on t1.id=t2.id
where t1.id not in (select id from table2)
but this is not working
SELECT t1.id
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id = t1.id
WHERE t2.id IS NULL
Conceptually, we select all rows from table1 and for each row we attempt to find a row in table2 with the same value for the id column. If there is no such row, we just leave the table2 portion of our result empty for that row. Then we constrain our selection by picking only those rows in the result where the matching row does not exist. Finally, We ignore all fields from our result except for the id column (the one we are sure that exists, from table1).
try this:
select id from table1 t1 where t1.id not in (select t2.id from table2 t2)
You don't need to join the two tables in this case. You could just do
select id from table1 A where A.id not in (select B.id from table2 B);
You could also just simply use the sql set difference EXCEPT operator to achieve this
(select id from table1) except (select id from table2);
Use NOT IN or NOT EXISTS
select id from table1 t1
where t1.id not in (select id from table2)
select id from table1 t1
where not exists (select id from table2 where id = t1.id)

How to check if two selects return the same ids

Suppose, we have query like this:
SELECT
1
FROM DUAL WHERE
(SELECT id FROM table_1 t1 WHERE /*conditions*/)
IN
(SELECT id FROM table_1 t2 WHERE /*conditions*/)
I want to check if first query
SELECT id FROM table_1 t1 WHERE /*conditions*/
returns the same ids like the second query.
Of course this query (IN statement) doesn't work.
Try:
SELECT id FROM table_1 t1 WHERE /*conditions1*/ and id not in (SELECT id FROM table_1 t2 WHERE /*conditions2*/)
union
SELECT id FROM table_1 t1 WHERE /*conditions2*/ and id not in (SELECT id FROM table_1 t2 WHERE /*conditions1*/)
If both queries gives you the same id's the result should be empty.
This will return nothing if sets are equal:
SELECT id FROM table_1 t1 WHERE /*conditions*/
EXCEPT
SELECT id FROM table_1 t2 WHERE /*conditions*/
You can use EXCEPT.
EXCEPT returns distinct rows from the left input query that aren’t
output by the right input query.
EXCEPT sample in your case:
SELECT id
FROM table_1 AS t1
WHERE /*conditions*/
EXCEPT
SELECT id
FROM table_1 AS t2
WHERE /*conditions*/
Just as an alternative method that used Full Join in tsql:
SELECT CASE WHEN isnull(Count(*), 0) > 1 then 1 else 0 end as result
FROM (SELECT t1.id as t1_id, t2.id as t2_id FROM
(SELECT id FROM table1 WHERE /*conditions*/) As t1
Full Outer Join
(SELECT id FROM table2 WHERE /*conditions*/) As t2
On t1.id = t2.id
) As ft
WHERE ft.t1_id is null or ft.t2_id is null
And I think this can marked as a stupid way.

Can I use the exists function in the select part of an SQL query?

I need to run a query where one of the fields returned is a yes or no if there is a row in another table matching one of the key fields in the first table.
Sounds like a job for join, except the second table is one to many and I just need to know if there are zero or a non zero number of rows in the secondary table.
I could do something like this:
select t1.name, t1.id, (select count(1) from t2 where t1.id=t2.id) from t1
but I'd like to avoid making an aggregate subquery if possible.
It was mentioned to me that I could use the exists() function, but I'm not seeing how to do that in a select field.
This is sybase 15 by the way.
You could still do the JOIN, something like this:
SELECT t1.name, t1.id, CASE WHEN t2.id IS NULL THEN 0 ELSE 1 END Existst2
FROM t1
LEFT JOIN (SELECT id FROM t2 GROUP BY id) t2
ON t1.id = t2.id
ahhh, I got it from another stackoverflow quetion...
case when exists (select * from t2 where t1.id = t2.id) then 1 else 0 end
I am just writing down the syntax here:
if exists (select * from table1 t1 inner join table1 t2 on t1.id = t2.id )
select * from table2
How about this query ( Work with all databases )
select t1.name, t1.id, 'Y' as HasChild
from t1
where exists ( select 1 from t2 where t2.id = t1.id)
UNION
select t1.name, t1.id, 'N' as HasChild
from t1
where NOT exists ( select 1 from t2 where t2.id = t1.id)