Oracle: Check for existence and map a new column - sql

Would like to check the existence of an id from table_1 in table_2 and based on that trying to create a new column mapped_value.
table_2 has huge number of records with duplicate id's and also has a non-unique index on it.
SQL> drop table table_1
Table dropped.
SQL> create table table_1(id varchar2(10),value varchar2(10))
Table created.
SQL> insert into table_1
(select '100','ABC' from dual
union all
select '101','DEF' from dual
union all
select '103','GHI' from dual
)
3 rows created.
SQL> commit
Commit complete.
SQL> select * from table_1
ID VALUE
---------- ----------
100 ABC
101 DEF
103 GHI
3 rows selected.
SQL> drop table table_2
Table dropped.
SQL> create table table_2(id varchar2(10),value varchar2(10),day date)
Table created.
SQL> insert into table_2
(select '100','ABC',sysdate from dual
union all
select '100','ABC',sysdate from dual
union all
select '100','ABC',sysdate from dual
union all
select '101','DEF',sysdate from dual
union all
select '101','DEF',sysdate from dual
union all
select '101','DEF',sysdate from dual
)
6 rows created.
SQL> commit
Commit complete.
SQL> select * from table_2
ID VALUE DAY
---------- ---------- ---------
100 ABC 18-SEP-18
100 ABC 18-SEP-18
100 ABC 18-SEP-18
101 DEF 18-SEP-18
101 DEF 18-SEP-18
101 DEF 18-SEP-18
6 rows selected.
Trying below but its getting duplicate records for ids 100 and 101.
I know,shouldn't use outer join as there are duplicates.
I want to get the desired output but without duplicates by leveraging the non-unique index on table_2.
How do go about this?
SQL> select t1.*,case when t2.id is null then '***EMPTY****' else t2.id end as mapped_value
from table_1 t1,table_2 t2
where t1.id = t2.id(+)
ID VALUE MAPPED_VALUE
---------- ---------- ------------
100 ABC 100
100 ABC 100
100 ABC 100
101 DEF 101
101 DEF 101
101 DEF 101
103 GHI ***EMPTY****
7 rows selected.

If I understand that correctly, an EXISTS in a CASE might be what you're after.
SELECT t1.id,
t1.value,
CASE
WHEN EXISTS (SELECT *
FROM table_2 t2
WHERE t2.id = t1.id) THEN
t1.id
ELSE
'***EMPTY***'
END mapped_value
FROM table_1 t1;

Related

Create a duplicate row on top of Select statement

table TEST
id
Name
1
abc
2
xyz
In general i used to get records from below query
Select id,name from TEST.
id
Name
1
abc
2
xyz
but now i want to create a duplicate for each row on top my select query
expected output: please suggest how can i achieve result like below
id
Name
1
abc
1
abc
2
xyz
2
xyz
You may cross join your table with a sequence table containing how ever many copies you want. Here is an example using an inline sequence table:
SELECT t1.id, t1.Name
FROM yourTable t1
CROSS JOIN (
SELECT 1 AS seq FROM dual UNION ALL
SELECT 2 FROM dual UNION ALL
SELECT 3 FROM dual
) t2
WHERE t2.seq <= 2
ORDER BY t1.id;
To me, UNION (ALL) set operator seems to be quite simple.
Sample data:
SQL> select * from test;
ID NAME
---------- ----
1 abc
2 xyz
UNION ALL:
SQL> select * from test
2 union all
3 select * from test;
ID NAME
---------- ----
1 abc
2 xyz
1 abc
2 xyz
SQL>
CREATE table test(
id integer,
name VARCHAR2(4)
);
INSERT into test (id, name) VALUES (1,'ABC');
INSERT into test (id, name) VALUES (2,'XYZ');
with data as (select level l from dual connect by level <= 2)
select *
from test, data
order by id, l
/
One more option is LATERAL
SELECT t.*
FROM test
, LATERAL (
SELECT id, name FROM DUAL
union all
SELECT id, name FROM DUAL
) t
One option is using a self-join along with ROW_NUMBER analytic function such as
WITH t AS
(
SELECT t1.id, t1.name, ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY 0) AS rn
FROM test t1,
test t2
)
SELECT id, name
FROM t
WHERE rn <= 2
Demo

Delete data from table1 based on data in table 2 with composite primary key

I have two tables in Oracle db. Table1 and table2. Both have composite primary key. Structure of the tables are same but not data.
I need to delete rows from table1 which are not in table2.
There are various options; you've already seen one in Impaler's post.
SQL> create table a (id1, id2, name) as
2 select 1, 10, 'Little' from dual union all
3 select 2, 20, 'Foot' from dual union all --> these two should be deleted
4 select 3, 30, 'Xyz' from dual; --> as (id1, id2) don't exist in table B
Table created.
SQL> create table b (id1, id2, name) as
2 select 1, 10, 'Mickey' from dual union all
3 select 4, 40, 'Mouse' from dual;
Table created.
NOT IN (the same as Impaler's, obviously):
SQL> delete from a
2 where (id1, id2) not in (select id1, id2 from b);
2 rows deleted.
SQL> select * from a;
ID1 ID2 NAME
---------- ---------- ------
1 10 Little
SQL> rollback;
Rollback complete.
NOT EXISTS:
SQL> delete from a
2 where not exists (select null from b
3 where b.id1 = a.id1
4 and b.id2 = a.id2
5 );
2 rows deleted.
SQL> select * from a;
ID1 ID2 NAME
---------- ---------- ------
1 10 Little
SQL> rollback;
Rollback complete.
IN, with the MINUS set operator:
SQL> delete from a
2 where (id1, id2) in (select id1, id2 from a
3 minus
4 select id1, id2 from b
5 );
2 rows deleted.
SQL> select * from a;
ID1 ID2 NAME
---------- ---------- ------
1 10 Little
SQL> rollback;
Rollback complete.
SQL>
You can do:
delete from t
where (a, b) not in (
select a, b from u
)
See running example at db<>fiddle.

MERGE with multiple UPDATE statements

Can we achieve below scenario using single MERGE statement:
source table - table1
destination table- table2
when table1.id in table2.id
then update table1 SET phone_number=123456
when table1.id not in table2.id
then update table1 SET phone_number=555555
Note:- i am able to achieve the result using below query .
MERGE INTO table1 tbl1
USING table2 tbl2
ON (tbl1.id = tbl2.id)
WHEN MATCHED THEN
UPDATE SET tbl1.phone_number=123456;
update table1 set phone_number = 555555 where id not in (select id from table2);
Is there any way to achieve it by using only MERGE Statement ?
When no rows are matched then you can not use UPDATE (in WHEN NOT MATCHED). as there are no rows matched then which data should be updated?
Normal merge statement must have following structure:
MERGE <hint> INTO <table_name>
USING <table_view_or_query>
ON (<condition>)
WHEN MATCHED THEN <update_clause>
DELETE <where_clause>
WHEN NOT MATCHED THEN <insert_clause>
[LOG ERRORS <log_errors_clause> <reject limit <integer | unlimited>];
When there is no match then there are no rows found by oracle into your target table which matches with source table using ON condition then how can it update the record? which record it will update?
WHEN NOT MATCHED is illustrated as following in oracle documentation:
You can handle your scenario using MERGE as follows:
-- Oracle data creation
SQL> CREATE TABLE table1 ( id number, phone_number number );
Table created.
SQL> INSERT INTO table1
2 SELECT 1, 111 from dual UNION ALL
3 SELECT 2, 222 from dual UNION ALL
4 SELECT 3, 333 from dual UNION ALL
5 SELECT 4, 444 from dual;
4 rows created.
SQL> drop table table2;
Table dropped.
SQL> CREATE TABLE table2 ( id number );
Table created.
SQL> INSERT INTO table2
2 SELECT 1 from dual UNION ALL
3 SELECT 2 from dual;
2 rows created.
-- Your merge statement
SQL> MERGE INTO TABLE1 TBL1
2 USING (
3 SELECT T1.ID, T2.ID AS T2ID
4 FROM TABLE1 T1
5 LEFT JOIN TABLE2 T2 ON T1.ID = T2.ID
6 )
7 TBL2 ON ( TBL1.ID = TBL2.ID )
8 WHEN MATCHED THEN
9 UPDATE SET TBL1.PHONE_NUMBER = NVL2(TBL2.T2ID, 123456, 555555);
4 rows merged.
-- Result
SQL> SELECT * FROM TABLE1;
ID PHONE_NUMBER
---------- ------------
1 123456
2 123456
3 555555
4 555555
SQL>
Cheers!!
Just use an UPDATE statement:
Oracle Setup:
CREATE TABLE table1 ( id, phone_number ) AS
SELECT 1, 1 FROM DUAL UNION ALL
SELECT 2, 2 FROM DUAL;
CREATE TABLE table2 ( id ) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 3 FROM DUAL;
Update:
UPDATE table1 t1
SET phone_number = COALESCE(
(
SELECT 123456
FROM table2 t2
WHERE t1.id = t2.id
),
555555
)
Output:
SELECT *
FROM table1
ID | PHONE_NUMBER
-: | -----------:
1 | 123456
2 | 555555
db<>fiddle here
The syntax you are looking for in a MERGE statement exists in SQL Server but is NOT valid in Oracle:
MERGE INTO table1 t1
USING table2 t2
ON ( t1.id = t2.id )
WHEN MATCHED THEN
UPDATE SET phone_number = 123456
WHEN NOT MATCHED BY SOURCE THEN
UPDATE SET phone_number = 555555;
db<>fiddle here

Update Syntax with joins

I am trying to update a column only with the matched condition.
update table1 set col=Match
where id in(select id from
table1,table2 where table1.id=table2.id);
It says sql command not properly ended.
Here's an example which shows what to do (at least, that's what I understood, based on the question and comments you posted).
Test case first:
SQL> create table table1 (id number, criteria varchar2(10));
Table created.
SQL> create table table2 (id number);
Table created.
SQL> insert into table1 (id)
2 select 1 from dual union all
3 select 2 from dual;
2 rows created.
SQL> insert into table2 (id)
2 select 1 from dual;
1 row created.
As you can see, both tables share ID = 1 so we'd expect its table1.criteria to be modified.
Your query:
SQL> update table1 set
2 criteria = 'M1'
3 where id in (select a.id
4 from table1 a join table2 b on a.id = b.id
5 );
1 row updated.
SQL> -- Result
SQL> select * From table1;
ID CRITERIA
---------- ----------
1 M1
2
Alternatively:
SQL> update table1 a set
2 a.criteria = 'M2'
3 where exists (select null
4 from table2 b
5 where b.id = a.id
6 );
1 row updated.
SQL> select * From table1;
ID CRITERIA
---------- ----------
1 M2
2
See if it helps.

Delete rows in two tables

I have tow tables
How to make pl/SQL procedure and then job when I delete from table1 where table1.S = Table2.Z and table1.O =90 and table2.P=90 same time to delete in table2
Create trigger for after delete event:
CREATE OR REPLACE TRIGGER trg_aftre_table1
AFTER DELETE
on table1
FOR EACH ROW
BEGIN
-- Delete from table2 when delete ant data from table1
delete from table2 where :OLD.S = Table2.Z and :OLD.O=table2.P ;
END;
That would be a trigger, not a procedure + job.
Here's an example: sample tables & trigger code, which specifies WHEN to fire:
SQL> create table t1 as
2 select 50 s, 90 o from dual union
3 select 51, 90 from dual union
4 select 50, 10 from dual;
Table created.
SQL> create table t2 as
2 select 50 z, 10 p from dual union
3 select 51, 10 from dual union
4 select 50, 90 from dual union
5 select 51, 90 from dual;
Table created.
SQL>
SQL> create or replace trigger trg_ad_t1
2 after delete on t1
3 for each row
4 when (old.o = 90)
5 begin
6 delete from t2
7 where z = :old.s
8 and p = :old.o;
9 end;
10 /
Trigger created.
OK, some deleting: first, one that won't affect TABLE 2:
SQL> delete from t1 where s = 50 and o = 10;
1 row deleted.
SQL> select * From t1;
S O
---------- ----------
50 90
51 90
SQL> select * From t2;
Z P
---------- ----------
50 10
50 90
51 10
51 90
SQL>
And now, the one that affects TABLE 2:
SQL> delete from t1 where s = 50 and o = 90;
1 row deleted.
SQL> select * From t1;
S O
---------- ----------
51 90
SQL> select * From t2;
Z P
---------- ----------
50 10
51 10
51 90
SQL>