ORACLE SQL:More than one WHEN MATCHED condition INSIDE MERGE STATEMENT - sql

I want to use a merge statement in pl/sql and the target table has to be updated on a particular condition. I know we can use multiple when matched condition in sql server with and operator, but i am not sure about Oracle. I am looking for that kind of feature in oracle.

create table table1 (id number, text varchar2(20));
create table table2 (id number, text varchar2(20), text2 varchar2(20));
insert into table1 values (1,'');
insert into table1 values (2,'');
insert into table1 values (3,'');
insert into table2 values (1,'a','b');
insert into table2 values (2,'a','b');
insert into table2 values (3,'a','b');
insert into table2 values (4,'a','b');
I understand you want obtain something like code below with commented line
merge into table1 t1
using table2 t2
on (t1.id = t2.id)
when matched then update set
t1.text = t2.text where t1.id = 1
--t1.text = t2.text2 where t1.id = 2
when not matched then insert values (t2.id, t2.text);
I would do that like:
merge into table1 t1
using (select id, case id when 1 then text when 2 then text2 else null end as tt, text from table2) t2
on (t1.id = t2.id)
when matched then update set
t1.text = t2.tt where t2.tt is not null
--t1.text = t2.text2 where t1.id = 2
when not matched then insert values (t2.id, t2.text);
select * from table1;

Related

Informix - where clause with merge into

I am using Informix Dynamic Server Version 12.10.FC9W1X2.
I need to update a table with fields from a different table. I am attempting to use the
MERGE INTO
statement, but I am not able to use a WHERE CLAUSE to filter out information from the table that is being updated as it's causing a syntax error. I also tried adding AND to the WHEN MATCHED and it isn't working.
Is there any way to do this?
This is my statement so far,
MERGE INTO table1 as t1
USING table2 as t2
ON t1.some_no = t2.some
WHEN MATCHED
THEN
UPDATE SET t1.some_other_no = t2.some_other_no, is_processed = 'Y', resolution = 'AAA'
The additional filters on table1 can be placed in the ON clause. For example:
create table t1(col1 int, col2 int, col3 int);
insert into t1 values(1,1,1);
insert into t1 values(1,2,0);
insert into t1 values(1,3,0);
insert into t1 values(2,1,0);
insert into t1 values(3,1,1);
create table t2 (col1 int, col2 int);
insert into t2 values(1,5);
insert into t2 values(2,5);
insert into t2 values(3,5);
merge into t1
using t2
on
t1.col1 = t2.col1
AND t1.col3 = 1
when matched then
update set t1.col2 = t2.col2;
The above results in the following output when selecting from the t1 table
col1 col2 col3
1 5 1
1 2 0
1 3 0
2 1 0
3 5 1

Oracle INSERT statement with selects on different tables

I have two tables table1 and table2. Those tables have unique name and id columns.
I also have a relation / join table, table1_table2 which has the straight-forward colums table1_id and table2_id.
What I want to do is to insert a new relation into table1_table2 knowing the names of the elements in table1 and table2 I want to create a relation for. But I need to get their ids to insert them into table_table2.
What I want is something like that:
insert into table1_table2 values ((select id from table1 where name = 'some_name'), (select id from table2 where name = 'another_name'))
I also tried using
insert into table1_table2 values ((select id from (select id from table1 where name = 'some_name') where rownum=1), (select id from (select id from table2 where name = 'another_name') where rownum=1))
which also didn't work.
I understand I can first extract the ids if necessary but I'd prefer it to be in one statement.
Edit: I've also tried
insert into table1_table2 values (select t1.id, t2.id from table1 t1, table2 t2 where t1.name = 'some_name' and t2.name = 'another_name')
which also didn't work
Example data:
table1
id name
1 foo
2 bar
table2
id name
1 some
2 data
table1_table2
table1.id table2.id
1 1
and now I want to insert
table1.id table2.id
2 2
into table1_table2, but I do only know that the entry in table1 has the name bar and the entry in table2 has the name data.
This should work:
INSERT INTO table1_table2 (table1_id, table2_id)
VALUES ( (SELECT id FROM table1 WHERE name = 'some_name'),
(SELECT id FROM table2 WHERE name = 'another_name')
);
However, I would write it as:
INSERT INTO table1_table2 (table1_id, table2_id)
SELECT t1.id, t2.id
FROM table1 t1 JOIN
table2 t2
ON t1.name = 'some_name' AND
t2.name = 'another_name';
Note in this case if there is no match in either table, then no row is inserted at all. Using VALUES, a NULL values would be inserted.

Update and insert to one table from another

I have two tables:
table1: (ID, Code, Name)
table2: (ID, Code, Name)
with same columns
I want to to insert data from table1 to table2 or update columns if that exists in table2 (table1.ID = table2.ID)
What is the simple way to do this?
WITH OUT MERGE
Merge table2 as target
using table1 as source
on
target.id=source.id
When matched
Then
update
set target.id=source.id,
target.name=source.name
When not matched by Target Then
INSERT (id, name) VALUES (id, name);
There are some issues with Merge statement,so it should be used with caution..
Further i recommend ,using merge as two seperate DML statements like below..
insert into table2
select * from table1 t1 where not exists (select 1 from table2 t2 where t2.id=t1.id)
update t2
set
t2.id=t1.id,
t2.name=t1.name
from
table1 t1
join
table2 t2
on t1.id=t2.id
Reasons being stated by Paul White here in his detailed answer..
MERGE table2 t2
USING table1 t1
ON t1.ID = t2.ID
WHEN MATCHED THEN
UPDATE
SET t2.Code = t1.Code, t2.Name = t1.Name
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID, Name, Code)
VALUES (t1.ID, t1.Name, t1.Code);
Assuming the ID column is unique and should not be set, it seems you could do it in two SQL Statements.
/* UPDATE the rows in TABLE2 */
UPDATE TABLE2
SET NAME = (SELECT NAME FROM TABLE1 WHERE TABLE1.CODE = TABLE2.CODE)
WHERE CODE IN (SELECT CODE FROM TABLE1)
/* INSERT the rows that are missing */
INSERT INTO TABLE2
(CODE, NAME)
(
SELECT CODE, NAME
FROM TABLE1
WHERE CODE NOT IN (SELECT CODE FROM TABLE2)
)
get all rows that are in table1 but not in table2
insert into table2(id, code, name)(
SELECT table1.*
FROM table1
LEFT JOIN table2 ON (table1.id = table2.id)
WHERE table2.C IS NULL
)
update table2
update table2 set name = (select name from table1 where table1.code = table2.code and table1.id = table2.id)
It might be worth looking at triggers on update and insert if you'd like to have this done manually
Inserting Date into target table once date is updated in source table
Here there is a working example:
create table Table1(id int,name varchar(100));
create table Table2(id int,name varchar(100));
create trigger Table1Trigger after insert on Table1 for each row begin
insert into Table2(id, name) values (new.id, new.name);
end;
Use the following queries to validate the results
insert into Table1 values(1,'John'),(2,'Smith'),(3,'Carol');
Here I am writing a script that use full when you want to update table2 from table1.
Update table2 set table2.code = table1.code, table2.name=table1.name from table1 where table2.id=table1.id
And if you want to insert then use this script.
Insert into table2 (id,code,name) select id,code,name from table1
If in table2 id is not auto increment.
Otherwise not insert the value of id column in table2.

Transfer data from temp table to physical table

I have this table named table1
id uniquefield field1 field2
1 11 test test2
2 12 test2 test3
and I have this value in my temp table #temp1
id uniquefield field1 field2
1 11 test test2
2 12 test2 test3
3 13 test4 test5
4 14 test5 test6
Now, what I want to happen is that I want to transfer all data from #temp1 table. It would insert if data does not exist in table1 table and would update if it exist.
Does anybody know how to do this using SQL Server or dynamic SQL?
Hope to find some response from you.
Temp tables are no different in such cases like you mentioned. The difference is they are only available to the current connection for the user; and they are automatically deleted when the user disconnects from instances. So you can handle these tables like any other SQL table and use a MERGE query to achieve this data manupulation.
Assuming the uniquefield column can be treated as link between these tables.
MERGE table1 t
USING #temp1 t1
ON t.uniquefield = t1.uniquefield
WHEN MATCHED THEN
UPDATE
SET t.id = t1.id,
t.field1 = t1.field1,
t.field2 = t1.field2
WHEN NOT MATCHED BY TARGET THEN
INSERT (id, uniquefield, field1, field2)
VALUES (t1.id, t1.uniquefield, t1.field1, t1.field2 );
You can DROP #temp1 after this and do a SELECT * FROM table1 to check the updated/ inserted data.
Assume 2 table row is identical by id, insert with not exists()
-- Append missing row to table1
INSERT table1
SELECT * FROM #temp1 t WHERE NOT EXISTS(SELECT * FROM table1 WHERE id = t.id)
Temp tables are no different in such cases like you mentioned. The difference is they are only available to the current connection for the user; and they are automatically deleted when the user disconnects from instances. So you can handle these tables like any other SQL table.
Assuming the uniquefield column can be treated as link between these tables.
Update statemant:
update table1
set
t.id = t1.id,
t.field1 = t1.field1,
t.field2 = t1.field2
from table1 t
join #temp1 t1
on t.uniquefield = t1.uniquefield
Insert statement:
insert into table1(id, uniquefield, field1, field2)
select t1.id, t1.uniquefield, t1.field1, t1.field2
from table1 t
join #temp1 t1
on t.uniquefield != t1.uniquefield
This is assuming that id is the table primary key. Otherwise replace appropriately.
UPDATE Table1
SET id= T.id,
Uniquefield = T.Uniquefield,
Field1 = T.field1,
Field2 = T.field2
FROM Table1
INNER JOIN #temp1 T ON T.id = Table1.id;
INSERT INTO Table1 (id, uniquefield, field1, field2)
SELECT id, uniquefield, field1, field2
FROM #temp1
WHERE id NOT IN (SELECT id FROM Table1)
I think the elegant way is to use MERGE here:
SET IDENTITY_INSERT table1 ON;
MERGE INTO table1 AS T
USING #temp1 AS S
ON S.id = T.id
WHEN MATCHED THEN
UPDATE SET
T.uniquefield = S.uniquefield,
T.field1 = S.field1,
T.field2 = S.field2
WHEN NOT MATCHED BY TARGET THEN
INSERT (id, uniquefield, field1, field2)
VALUES (S.id, S.uniquefield, S.field1, S.field2);
SET IDENTITY_INSERT table1 OFF;
I have added the IDENTITY_INSERT there just in case ID column in your table1 is an IDENTITY and you might want to keep the one from #temp1 table. If you dont need / have IDENTITY, just remove those lines.
you can simply use this query:-
insert into table1
select * from (
select #temp.workersID,#temp.W_name,#temp.salary,#temp.joining_year,#temp.city,#temp.id
from #temp
full join workers
on #temp.WorkersID = workers.WorkersID
where workers.WorkersID is null
) ds

update one table with data from another using the common key

update one table with data from another using the common key
create table table1 (
id varchar2(4),
name varchar2(10),
desc_ varchar2(10)
)
create table table2 (
id varchar2(4),
id_new varchar2(4)
)
insert into table1 values('1111', 'a', 'abc')
insert into table1 values('2222', 'b', 'def')
insert into table1 values('3333', 'c', 'ghi')
insert into table1 values('4444', 'd', 'jkl')
insert into table2 values('1111', '8080')
insert into table2 values('2222', '9090')
merge into table1 t1
using (select * from table2) t2
on (t1.id = t2.id)
when matched then update set t1.id = t2.id_new
error: ORA-27432: step does not exist for chain .
This should work:
update table1 t1
set id = coalesce((
select id_new
from table2 t2
where t1.id = t2.id), id);
SQL Fiddle Demo
Here's an alternative approach with merge:
merge into table1 t1
using (select * from table2) t2
on (1 = 1)
when matched then update set t1.id = t2.id_new where t1.id = t2.id
More Fiddle
Probably best speed you'll obtain using:
merge into table1 t1
using (select t1.rowid rw, t2.id_new
from table2 t2
join table1 on (table1.id = t2.id)
) s
on t1.rowid = s.rowid
when matched then update set t1.id = s.id_new;
However it depends on optimizer(previous answers may have a good behavior if CBO intuits your desire)