INNER JOIN on multiple columns with multiple matches - oracle

How to find what rows got exact one match and what rows got more than one match in a INNER JOIN ?
SELECT A.Col1, B.Col2 FROM A INNER JOIN B
ON A.Col3 = B.Col3 AND A.Col4 = B.Col4;
As we know INNER JOIN returns rows with minimum one match, so to again reiterate my qustion, how to find which rows matched once and which rows got more than one match.
Regards,
Sachin

You could use a window function to count how many records are coming from B:
SELECT A.Col1, B.Col2, Count(*) OVER (PARTITION BY b.col3, b.col4) as bcount
FROM A
INNER JOIN B
ON A.Col3 = B.Col3 AND A.Col4 = B.Col4;

With the help of JNevill's inputs, here is a working example of what I was looking for. I want to thank JNevill once again.
create table A (col1 number, col3 number, col4 number, col5 number, col6 number);
create table B (col2 number, col3 number, col4 number, col5 number, col6 number);
insert into A values (1,2,3, 4, 5);
insert into A values (2,3,4,5,6);
insert into B values (3,4,5,6,7);
insert into B values (4,2,3,4,5);
insert into B values (5,2,3,8,9);
insert into B values (6,3,4,5,6);
insert into B values (7,3,4,5,6);
SELECT Col1 FROM(
SELECT A.Col1,B.Col2, A.Col3, A.Col4, A.Col5 ,A.Col6, Count(*) OVER (PARTITION BY B.col3, B.col4, B.col5, B.col6) as bcount
FROM A
INNER JOIN B
ON A.Col3 = B.Col3 AND A.Col4 = B.Col4 AND A.Col5 = B.Col5 AND A.Col6 = B.Col6) WHERE BCOUNT = 1;
So, I was looking for a column from table A which has exact one match for all the joining columns in table B.
Regards.

Related

How can I count the amount of values in different columns in oracle plsql

For example, I have a table with these values:
ID
Date
Col1
Col2
Col3
Col4
1
01/11/2021
A
A
B
2
01/11/2021
B
B
The A and B values are dynamic, they can be other characters as well.
Now I need somehow to get to the result that id 1 has 2 occurences of A and one of B. Id 2 has 0 occurences of A and 2 occurences of B.
I'm using dynamic SQL to do this:
for v_record in table_cursor
loop
for i in 1 .. 4
loop
v_query := 'select col'||i||' from table where id = '||v_record.id;
execute immediate v_query into v_char;
if v_char = "any letter I'm checking" then
amount := amount + 1;
end if;
end loop;
-- do somehting with the amount
end loop;
But there has to be a better much more efficient way to do this.
I don't have that much knowledge of plsql and I really don't know how to formulate this question in google. I've looked into pivot, but I don't think that will help me out in this case.
I'd appreciate it if someone could help me out.
Assuming the number of columns would be fixed at four, you could use a union aggregation approach here:
WITH cte AS (
SELECT ID, Col1 AS val FROM yourTable UNION ALL
SELECT ID, Col2 FROM yourTable UNION ALL
SELECT ID, Col3 FROM yourTable UNION ALL
SELECT ID, Col4 FROM yourTable
)
SELECT
t1.ID,
t2.val,
COUNT(c.ID) AS cnt
FROM (SELECT DISTINCT ID FROM yourTable) t1
CROSS JOIN (SELECT DISTINCT val FROM cte) t2
LEFT JOIN cte c
ON c.ID = t1.ID AND
c.val = t2.val
WHERE
t2.val IS NOT NULL
GROUP BY
t1.ID,
t2.val;
This produces:
Demo

joining based on columns priority

I want to join 2 tables based on columns priority
ex. Suppose Table1 has six columns(Col1,Col2,Col3,Col4,Col5,Col6)
If i want to join Table 1 with table2 (Col1,Col2,Col3,Col4,Col5,Col7), it should
otherwise
Select Table2.col7
where
first check col1 , col2 and col3 if match found no need go check more
second check col1 , col2 if match found no need go check more
third check col1 if match found no need go check more
last ignore all col1 , col2 and col3
AND Table1.Col4=Table2.Col4
AND Table1.Col5=Table2.Col5
I may not be clear with my words, if any concern please shout
You cannot tell SQL to try to join on a certain condition first and in case it finds no match to go on searching. What you can do is join all allowed combinations (matches on col4 and col5 in your case) and then rank your matches (such that a match on col1 and col2 and col3 is considered best etc.). Then only keep the best matches:
select col7
from
(
select
t1.*,
t2.*,
row_number() over
(
partition by t1.col4, t1.col5
order by case
when t2.col1 = t1.col1 and t2.col2 = t1.col2 and t2.col3 = t1.col3 then 1
when t2.col1 = t1.col1 and t2.col2 = t1.col2 then 2
when t2.col1 = t1.col1 then 3
else 4
) as rn
from table1 t1
join table2 t2 on t2.col4 = t1.col4 and t2.col5 = t1.col5
)
where rn = 1;
Select t2.col7
from Table1 t1 inner join Table2 t2
on
case
when t1.col1 = t2.col1 then 1
when t1.col2 = t2.col2 then 1
when t1.col3 = t2.col3 then 1
when t1.Col4=t2.Col4
and t1.Col5=t2.Col5 then 1
else 0 end = 1
;

Generate difference between 2 tables listing columns from both tables

Have 2 tables with same columns and want to generate the difference between the tables and want to show the difference listing all columns from both tables
example:
select a.*,b.* from (
(
select a.col1,a.col2 from
(select col1, col2 from table1 minus select col1, col2 from table2) as a
)
union
(
select b.col1, b.col2 from
(select col1, col2 from table2 minus select col1, col2 from table2) as b
)
)
The result should be
a.col1 a.col2 b.col1 b.col2
a.FName a.ZipCode b.FName b.ZipCode
John <same value> Jane <same value as A>
Alpha 1234 Beta 2345
My query returns exception that it is missing R parenthesis after the 1st minus keyword
I think you are trying to find rows from table a which are missing in table b and rows in table b which are missing from table a. However, there is no point in joining these two sets. Try the following query and see if it works for you.
SELECT col1, col2, 'Missing from table 2' title
FROM
(
SELECT col1,
col2
FROM table1
MINUS
SELECT col1,
col2
FROM table2
)
UNION ALL
SELECT col1, col2, 'Missing from table 1' title
FROM
(
SELECT col1,
col2
FROM table2
MINUS
SELECT col1,
col2
FROM table1
)

oracle insert into column using subquery

I want to insert data into a column in the table.
Table a
ID col1 col2
1 A null
2 B null
Table b
ID col1
1 C
2 D
Expected results:
Table A
ID col1 col2
1 A C
2 B D
I tried this:
insert into tableA (col2)
select b.col1
from tableB b , tableA a
where b.id = a.id
and I received
0 row inserted.
How do I insert the col1 in B into col2 in A for the matching 'id' columns?
Thank you.
You must use Merge statement when inserting based on joins.
Also in table tableA col2 already exist but you want to insert a value on join then you must update that column.
merge into tablea a
using tableb b
on (b.id = a.id)
when matched
then
update set a.col2 = b.col1;
What you want to do shouldn't require a subquery. I'm not a huge fan of the table a, table b notation, try this:
update a
set col2 = b.col1
from tableB b
join tableA a
on a.id = b.id

How to handle no rows returned in an Oracle update using a common sub-select

Consider the update:
UPDATE table1
SET c1 = NVL(( SELECT d1 FROM table2 WHERE table1.id = table2.id ), 0),
c2 = NVL(( SELECT d2 FROM table2 WHERE table1.id = table2.id ), 0)
The NVL function handles the case where the sub-select returns no rows.
Is there a good way to rewrite this (without repeating the sub-select) using this type of syntax:
UPDATE table1 SET (c1,c2) = ( SELECT d1, d2 FROM table2 where table1.id = table2.id )
such that the case where the sub-select returns now rows is handled.
I would change the subselect to include a left outer join on t1, and then nvl the results in that case, eg:
drop table t1;
drop table t2;
create table t1 (col1 number, col2 number, col3 number);
create table t2 (col1 number, col2 number, col3 number);
insert into t1 values (1, 10, 100);
insert into t1 values (2, 20, 200);
insert into t2 values (1, 100, 1000);
commit;
update t1
set (col2, col3) = (select nvl(col2, 0), nvl(col3, 0)
from (select a.col1, b.col2, b.col3
from t1 a
left outer join t2 b on (a.col1 = b.col1)) c
where c.col1 = t1.col1);
commit;
select * from t1;
COL1 COL2 COL3
---------- ---------- ----------
1 100 1000
2 0 0

Resources