MERGE with multiple UPDATE statements - sql

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

Related

sql select values from another table if exist

Please help, need to select from table 1, but if entry with the same id exists in table2 should return name and last name from there otherwise values from table1
table1
id|name|lastname
1 | |
2 | |
3 | |
table2
id|name|lastname
3 | |
Tried this, but not working
SELECT ID, NAME, LASTNAME
FROM table1
WHERE EXISTS
(SELECT 1 FROM table2 WHERE table2.ID = table1.ID)
if entry with the same id exists in table2 should return name and last name from there otherwise values from table1
You want a LEFT OUTER JOIN and then to use COALESCE:
SELECT t1.id,
COALESCE( t2.name, t1.name ) AS name,
COALESCE( t2.lastname, t1.lastname ) AS last_name
FROM table1 t1
LEFT OUTER JOIN table2 t2
ON ( t1.id = t2.id )
Which, for your sample data:
CREATE TABLE table1 ( id, name, lastname ) AS
SELECT 1, 'Alice1', 'Abbot1' FROM DUAL UNION ALL
SELECT 2, 'Betty1', 'Baron1' FROM DUAL UNION ALL
SELECT 3, 'Carol1', 'Casey1' FROM DUAL;
CREATE TABLE table2 ( id, name, lastname ) AS
SELECT 3, 'Carol2', 'Casey2' FROM DUAL;
Outputs:
ID
NAME
LAST_NAME
3
Carol2
Casey2
2
Betty1
Baron1
1
Alice1
Abbot1
db<>fiddle here

Combining and checking table value on SQL (ORACLE)

Table 1
no name col1
1 a a_1
2 b b_1
Table 2
id name parent
a_1 zz c_1
b_1 yy d_1
c_1 aa null
d_1 bb e_1
e_1 dd1 null
what i want to show is showing the all list name. for example table 1 name a has col1 name a_1 it will show the name on table 2, and then check the parent in the table 2 and show it and keep checking until it found null. the example is like below.. im sorry for my bad explanation
t1_name t2_name t2_name t2_name
a zz aa
b yy bb dd1
or shows like below
t1_name t2_name
a aa/zz
b dd1/bb/yy
what I've done is this query
select t1.name,t2.name as folder from table1 as t1 inner join table2 as t2 on t1.col1=t2.id
and I don't know how to check again in query... I am using oracle version 12.2.0.1.0 in SQL developer any help?
You want to get the rows from the first table and then recursively fetch all the rows from the second table until you reach a null parent, so you do:
with cte(NAME,
PARENT,
CURRENTPATH) as
(select t1.NAME,
t2.PARENT,
t2.NAME as CURRENTPATH
from TABLE1 t1
join TABLE2 t2 on t1.COL1 = t2.ID
union all
select t1.NAME,
t2.PARENT,
t1.CURRENTPATH || '/' || t2.NAME as CURRENTPATH
from cte t1
join TABLE2 t2 on t2.ID = t1.PARENT)
select NAME,
CURRENTPATH
from cte
where PARENT is null;
You can use the hierarchical query as following:
SQL> -- Your data
SQL> with table1(no,name,col1) as
2 (SELECT 1, 'a','a_1' FROM DUAL UNION ALL
3 SELECT 2, 'b','b_1' FROM DUAL
4 ),
5 table2 (id, name, parent) as
6 (select 'a_1', 'zz', 'c_1' from dual union all
7 select 'b_1', 'yy', 'd_1' from dual union all
8 select 'c_1', 'aa', null from dual union all
9 select 'd_1', 'bb', 'e_1' from dual union all
10 select 'e_1', 'dd1', null from dual)
11 -- Your query starts from here
12 SELECT
13 T1.NAME AS T1_NAME,
14 T2.NAMES AS T2_NAMES
15 FROM TABLE1 T1
16 JOIN (
17 SELECT
18 T2.ID,
19 SYS_CONNECT_BY_PATH(T2.NAME, '/') AS NAMES,
20 ROW_NUMBER() OVER(PARTITION BY ID ORDER BY LEVEL DESC) AS L
21 FROM TABLE2 T2
22 CONNECT BY T2.PARENT = PRIOR T2.ID
23 ) T2 ON T1.COL1 = T2.ID
24 WHERE L = 1;
T1_NAME T2_NAMES
------- ---------------
a /aa/zz
b /dd1/bb/yy
SQL>
Cheers!!
Which Oracle version are you using?

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.

multiple select in sql server

I want to search between 2 tables but that field i want to search is foreign key in other table
my tables are like this:
table 1
ID TitleSR
1 888
2 999
table 2
ID TitleSR
1 11
2 22
3 33
4 44
table contain value
ID value
11 italy
22 swiss
888 lilium
999 mount
33 england
I think I understand you. Try this one:
Select *
From table3 as VCT Inner Join
(Select * From table1
Union
Select * From table2) as FGT
On VCT.ID = FGT.TitleSR
Where value = 'italy';
You can use either of these methods:
Returns only t1 fields
SELECT * FROM Table1 t1
WHERE t1.ID in (SELECT ID FROM Table2);
Returns ALL fields
SELECT * FROM Table1 t1
JOIN Table2 t2 on t1.ID = t2.ID;
If your 'values' exist in a separate table (tblValues), you can use any of these:
Returns tblValues fields
SELECT * FROM tblValues tval
WHERE tval.ID in (SELECT TitleSR FROM Table1);
returns ALL fields
SELECT *
FROM (tblValues tval
JOIN Table1 t1 on tval.ID = t1.TitleSR)
JOIN Table2 on tval.ID = Table2.TitleSR;

Trying to get my delete statement to work

I want to remove rows from a table, based on a column from another table as such:
Table1: Table2:
value value, i
If table2.i is less than 1, delete corresponding row from table1 (but keep it in table2).
The problem is that value isn't unique, so if I have this for exampe:
Table1 table2
+-------+ +-----------+
| value | | value | i |
+-------+ +-----------+
| 5 | | 5 | 0 |
| 3 | | 5 | 3 |
+-------+ | 3 | 0 |
| 3 | 0 |
+-----------+
Value 3 should be deleted from table1 (since all occurrences in table2 has i<1) but value 5 should stay(because of i=3 row in table2)
My code so far (doesn't work):
DELETE FROM Table1, Table2
WHERE (SELECT MIN(Table2.i) FROM Table1, Table2
WHERE Table1.value = Table2.value) < 1;
Problem is: since my subquery returns min for ALL rows, everything gets deleted.
And I can't use "group by" in my subquery because then my comparison isn't allowed.
Try this one:
DELETE FROM Table1
WHERE NOT EXISTS(SELECT 1
FROM Table2
WHERE Table2.i > 0
AND Table2.value = Table1.value)
I dont know why you are using min, instead u should use max:
try this
DELETE FROM Table1
WHERE Table1.value1 = Table2.value1
and (SELECT MAX(Table2.i) FROM Table2
WHERE Table1.value1 = Table2.value1) < 1;
Ok, I'd start by writing a query that selects the rows you want to delete,
SELECT
*
FROM
Table1
EXCEPT
(
SELECT
t1.value
FROM
Table1 t1
JOIN
Table2 t2
ON t2.value = t1.value
WHERE
t2.i > 0
);
See Fiddle
Then change the SELECT to a DELETE
DELETE Table1
FROM
Table1 t1
WHERE
t1.value NOT IN
(
SELECT
t1.value
FROM
Table1 t1
JOIN
Table2 t2
ON t2.value = t1.value
WHERE
t2.i > 0
);
See Fiddle
How about:
delete from table1 where value in
(select value from table2 group by value having max(i) < 1)
Grouping table 2 by value and using having to detect where the maximum is less than 1 allows you to select the correct values for deletion from table 1.
having is basically a where clause which comes into play after aggregation so can be used with max and so on.
Here's a script to show it in action:
DROP TABLE TABLE1;
DROP TABLE TABLE2;
CREATE TABLE TABLE1 (VALUE INTEGER);
CREATE TABLE TABLE2 (VALUE INTEGER, I INTEGER);
INSERT INTO TABLE1 VALUES (5);
INSERT INTO TABLE1 VALUES (3);
INSERT INTO TABLE2 VALUES (5, 0);
INSERT INTO TABLE2 VALUES (5, 3);
INSERT INTO TABLE2 VALUES (3, 0);
INSERT INTO TABLE2 VALUES (3, 0);
SELECT * FROM TABLE1;
SELECT * FROM TABLE2;
DELETE FROM TABLE1 WHERE VALUE IN
(SELECT VALUE FROM TABLE2 GROUP BY VALUE HAVING MAX(I) = 0);
SELECT * FROM TABLE1;
SELECT * FROM TABLE2;
The output of this script is shown below. First, the setting up of all the tables:
DROP TABLE TABLE1; DROP TABLE TABLE2;
TABLE1 DROPPED
TABLE2 DROPPED
CREATE TABLE TABLE1 (VALUE INTEGER);
TABLE1 CREATED
CREATE TABLE TABLE2 (VALUE INTEGER, I INTEGER);
TABLE2 CREATED
INSERT INTO TABLE1 VALUES ((5), (3));
INSERTED 2 ROWS
INSERT INTO TABLE2 VALUES ((5, 0), (5, 3), (3,0), 3, 0));
INSERTED 4 ROWS
And display them to ensure they're as expected:
SELECT * FROM TABLE1; SELECT * FROM TABLE2;
VALUE
-----
5
3
VALUE I
----- -
5 0
5 3
3 0
3 0
Then run the command to get rid of the relevant rows:
DELETE FROM TABLE1 WHERE VALUE IN
(SELECT VALUE FROM TABLE2 GROUP BY VALUE HAVING MAX(I) = 0);
DELETED 1 ROW
And you can see that the 3` row has disappeared from table 1 as desired:
SELECT * FROM TABLE1; SELECT * FROM TABLE2;
VALUE
-----
5
VALUE I
----- -
5 0
5 3
3 0
3 0