My tables are as follows:
SELECT * FROM r_a;
CLASS SECTION
----- -------
1 A
1 B
2 A
2 B
SELECT * FROM r_b;
CLASS SECTION
----- -------
1 B
1 C
2 B
2 C
I want to perform a full outer join on these tables over the column SECTION where CLASS=1 in both tables. My desired output is :
SECTION SECTION_1
------- ---------
B B
A (Null)
(Null) C
However, the following query yields only the matching row, similar to result of an inner join.
**QUERY 1**
SELECT a.section, b.section
FROM
r_a a
FULL OUTER JOIN
r_b b
ON a.section=b.section
WHERE A.class=1 AND B.class=1
SECTION SECTION_1
------- ---------
B B
I am able to achieve desired result by taking the where conditions inside a nested query:
**QUERY 2**
SELECT a.section, b.section
FROM
(SELECT SECTION FROM r_a WHERE class=1) a
FULL OUTER JOIN
(SELECT SECTION FROM r_b WHERE class=1) b
ON a.section=b.section
SECTION SECTION_1
------- ---------
B B
(Null) C
A (Null)
The result is more surprising when the where conditions in **Query 1** is moved to the on clause:
** Query 3**
SELECT a.section, b.section
FROM
r_a a
FULL OUTER JOIN
r_b b
ON a.section=b.section AND A.class=1 AND B.class=1
SECTION SECTION_1
------- ---------
B B
(Null) C
(Null) B
(Null) C
B (Null)
A (Null)
A (Null)
MORE CLARITY:
*************
SELECT *
FROM
r_a a
FULL OUTER JOIN
r_b b
ON a.section=b.section AND A.class=1 AND B.class=1
CLASS SECTION CLASS_1 SECTION_1
------ ------- ------- ---------
1 B 1 B
(Null) (Null) 1 C
(Null) (Null) 2 B
(Null) (Null) 2 C
2 B (Null) (Null)
2 A (Null) (Null)
1 A (Null) (Null)
Explanation on why Query 1 doesn't produce the desired result and why Query 3 joins on class=2 even when the on clause says AND A.class=1 AND B.class=1 is greatly appreciated.
You first query is 100% perfect, just change your WHERE statement to OR instead of AND.
SELECT a.section, b.section
FROM
r_a a
FULL OUTER JOIN
r_b b
ON a.section=b.section
WHERE A.class=1 OR B.class=1
That is essentially what you are doing when you do your second attempt with the subqueries.
Keeping in mind that your WHERE clause is executed AFTER the FROM clause. When you use AND here you are saying "Only take results AFTER the join where both conditions are true." Obviously this dumps results when one table has a condition = 1 and the other does not. With the "OR" you are saying "Take results AFTER the join where either condition is true".
Be careful, condition where vs condition on is difference:
where is a filter which is applied after rows are selected using the join. It is not always the case that a join ... on condition is sematically equivalent to a where condition. You can see more detail here.
Your Query 1 <=>
select asection, bsection from(
SELECT a.section asection, b.section bsection, a.CLASS a, b.CLASS b
FROM r_a a
FULL OUTER JOIN r_b b
ON a.section=b.section
)
WHERE a=1 AND b=1
Related
Can any one tell me whether below 2 queries are an example of Left Outer Join or Right Outer Join??
Table Part:
Name Null? Type
PART_ID NOT NULL VARCHAR2(4)
SUPPLIER_ID VARCHAR2(4)
PART_ID SUPPLIER_ID
P1 S1
P2 S2
P3
P4
Table Supplier:
Name Null? Type
SUPPLIER_ID NOT NULL VARCHAR2(4)
SUPPLIER_NAME NOT NULL VARCHAR2(20)
SUPPLIER_ID SUPPLIER_NAME
S1 Supplier#1
S2 Supplier#2
S3 Supplier#3
Display all the parts irrespective of whether any supplier supplies them or not:
SELECT P.Part_Id, S.Supplier_Name
FROM Part P, Supplier S
WHERE P.Supplier_Id = S.Supplier_Id (+)
SELECT P.Part_Id, S.Supplier_Name
FROM Part P, Supplier S
WHERE S.Supplier_Id (+) = P.Supplier_Id
TableA LEFT OUTER JOIN TableB is equivalent to TableB RIGHT OUTER JOIN Table A.
In Oracle, (+) denotes the "optional" table in the JOIN. So in your first query, it's a P LEFT OUTER JOIN S. In your second query, it's S RIGHT OUTER JOIN P. They're functionally equivalent.
In the terminology, RIGHT or LEFT specify which side of the join always has a record, and the other side might be null. So in a P LEFT OUTER JOIN S, P will always have a record because it's on the LEFT, but S could be null.
See this example from java2s.com for additional explanation.
To clarify, I guess I'm saying that terminology doesn't matter, as it's only there to help visualize. What matters is that you understand the concept of how it works.
RIGHT vs LEFT
I've seen some confusion about what matters in determining RIGHT vs LEFT in implicit join syntax.
LEFT OUTER JOIN
SELECT *
FROM A, B
WHERE A.column = B.column(+)
RIGHT OUTER JOIN
SELECT *
FROM A, B
WHERE B.column(+) = A.column
All I did is swap sides of the terms in the WHERE clause, but they're still functionally equivalent. (See higher up in my answer for more info about that.) The placement of the (+) determines RIGHT or LEFT. (Specifically, if the (+) is on the right, it's a LEFT JOIN. If (+) is on the left, it's a RIGHT JOIN.)
Types of JOIN
The two styles of JOIN are implicit JOINs and explicit JOINs. They are different styles of writing JOINs, but they are functionally equivalent.
See this SO question.
Implicit JOINs simply list all tables together. The join conditions are specified in a WHERE clause.
Implicit JOIN
SELECT *
FROM A, B
WHERE A.column = B.column(+)
Explicit JOINs associate join conditions with a specific table's inclusion instead of in a WHERE clause.
Explicit JOIN
SELECT *
FROM A
LEFT OUTER JOIN B ON A.column = B.column
These
Implicit JOINs can be more difficult to read and comprehend, and they also have a few limitations since the join conditions are mixed in other WHERE conditions. As such, implicit JOINs are generally recommended against in favor of explicit syntax.
You can see answers from previous posts
However I added little more information
create table r2020 (id int, name varchar2(50),rank number);
insert into r2020 values (101,'Rob Rama',1);
insert into r2020 values (102,'Ken Krishna',3);
insert into r2020 values (108,'Ray Rama',2);
insert into r2020 values (109,'Kat Krishna',4);
create table r2021 (id int, name varchar2(50),rank number);
insert into r2021 values (102,'Ken Krishna',1);
insert into r2021 values (103,'Tom Talla',2);
insert into r2021 values (108,'Ray Rama',2);
--LEFT OUTER JOIN
--oracle notation
select * from r2020 r1, r2021 r2
where r1.id = r2.id (+)
order by r1.id;
--ANSI notation
select * from r2020 r1
left outer join r2021 r2 on r1.id = r2.id
order by r1.id;
--OUT PUT
NAME ID RANK NAME_1 ID_1 RANK_1
---- -- ---- ---- ---- ------
Rob Rama 101 1 (null) (null) (null)
Ken Krishna 102 3 Ken Krishna 102 1
Ray Rama 108 2 Ray Rama 108 2
Kat Krishna 109 4 (null) (null) (null)
--RIGHT OUTER JOIN
--oracle notation
select * from r2020 r1, r2021 r2
where r1.id (+) = r2.id
order by r1.id;
--ANSI notation
select * from r2020 r1
right outer join r2021 r2 on r1.id = r2.id
order by r1.id;
--OUT PUT
NAME ID RANK NAME_1 ID_1 RANK_1
---- -- ---- ---- ---- ------
Ken Krishna 102 3 Ken Krishna 102 1
Ray Rama 108 2 Ray Rama 108 2
(null) (null) (null) Tom Talla 103 2
--<b>MULTIPLE COLUMNS IN JOIN CONDITION</b>
--LEFT OUTER JOIN
--oracle notation
select * from r2020 r1, r2021 r2
where r1.id = r2.id (+) and
r1.rank = r2.rank (+)
order by r1.id;
--ANSI notation
select * from r2020 r1
left outer join r2021 r2 on r1.id = r2.id and
r1.rank = r2.rank
order by r1.id;
--OUT PUT
NAME ID RANK NAME_1 ID_1 RANK_1
---- -- ---- ---- ---- ------
Rob Rama 101 1 (null) (null) (null)
Ken Krishna 102 3 (null) (null) (null)
Ray Rama 108 2 Ray Rama 108 2
Kat Krishna 109 4 (null) (null) (null)
--RIGHT OUTER JOIN
--oracle notation
select * from r2020 r1, r2021 r2
where r1.id (+) = r2.id and
r1.rank(+) = r2.rank
order by r1.id;
--ANSI notation
select * from r2020 r1
right outer join r2021 r2 on r1.id = r2.id and
r1.rank = r2.rank
order by r1.id;
--OUT PUT
NAME ID RANK NAME_1 ID_1 RANK_1
---- -- ---- ---- ---- ------
(null) (null) (null) Ken Krishna 102 1
Ray Rama 108 2 Ray Rama 108 2
(null) (null) (null) Tom Talla 103 2
There is some incorrect information in this thread. I copied and pasted the incorrect information:
LEFT OUTER JOIN
SELECT *
FROM A, B
WHERE A.column = B.column(+)
RIGHT OUTER JOIN
SELECT *
FROM A, B
WHERE B.column(+) = A.column
The above is WRONG!!!!! It's reversed. How I determined it's incorrect is from the following book:
Oracle OCP Introduction to Oracle 9i: SQL Exam Guide. Page 115 Table 3-1 has a good summary on this. I could not figure why my converted SQL was not working properly until I went old school and looked in a printed book!
Here is the summary from this book, copied line by line:
Oracle outer Join Syntax:
from tab_a a, tab_b b,
where a.col_1 + = b.col_1
ANSI/ISO Equivalent:
from tab_a a left outer join
tab_b b on a.col_1 = b.col_1
Notice here that it's the reverse of what is posted above. I suppose it's possible for this book to have errata, however I trust this book more so than what is in this thread. It's an exam guide for crying out loud...
I want one flag in output of full outer join in oracle saying from_table which show this tows is fron which table in outer join.
For ex
A full outer join will give you the union of A and B, i.e. all the rows in A and all the rows in B. If something in A doesn't have a corresponding datum in B, then the B portion is null, and vice versa.
select * from a FULL OUTER JOIN b on a.a = b.b;
a | b
-----+-----
1 | null
2 | null
3 | 3
4 | 4
null | 6
null | 5
I need below output:
a | b | from_table
-----+-----
1 | null | A
2 | null | A
3 | 3 | both
4 | 4 | both
null | 6 | B
null | 5 | B
Kindly suggest the query
select a.*, b.*,
case when a.a is not null and b.b is not null then 'both'
when a.a is not null then 'a'
else 'b'
end as from_table
from a
FULL OUTER JOIN b on a.a = b.b;
SQLFiddle Demo
It's eligible to use nvl and nvl2 functions consecutively :
select a, b, decode(sign(nvl2(x,1,0)*nvl2(y,1,0)),1,'both',nvl(x,y)) "from_table"
from
(
select a.*, b.*, nvl2(a,'A',null) x, nvl2(b,'B',null) y
from a FULL OUTER JOIN b on a.a = b.b order by a,b
);
demo
I am trying to join two tables that look like the following:
Table 1
Letter | Value
A 2
B 5
Table 2
Letter | Number
A 1
C 7
I am trying to join these tables so that, regardless of what is in the tables at the time, there will always be an A,B,C record in the result. In other words, this would be displayed:
Letter | Value | Number
A 2 1
B 5 null
C null 7
The three letter records should always be displayed regardless of if they are in the tables. So assume table2 looks like this:
Letter | Number
A 1
Then I want the following results even though there is now no 'C' record:
Letter | Value | Number
A 2 1
B 5 null
C null null
Could anyone show how to do this?
You can use a SELECT ... FROM DUAL with a CONNECT BY clause to generate a stable set of letters in case some letters don't appear in either table.
with base_set_of_letters as (
select chr(rownum + 64) as Letter -- ascii 65=A, 66=B, 67=C, ...
from dual
connect by rownum <= 3) -- increase this number if you want more letters
select l.letter, t1.value, t2.xNumber
from base_set_of_letters l
left join Table1 t1 on t1.letter = l.letter
left join Table2 t2 on t2.letter = l.letter
order by l.letter;
SQL Fiddle Demo
If you were just looking to get all rows that existed joined, irregardless of whether data existed on both sides of the relationship, you'd be looking for a FULL OUTER JOIN:
SELECT COALESCE(t1.LETTER, t2.LETTER) AS LETTER,
t1.VALUE,
t2.NUM
FROM TABLE_1 t1
FULL OUTER JOIN TABLE_2 t2
ON t2.LETTER = t1.LETTER
ORDER BY COALESCE(t1.LETTER, t2.LETTER);
which produces
LETTER VALUE NUM
A 2 1
B 5 (null)
C (null) 7
But this would only give you rows where you've got a key value ('A', 'B', or 'C') - however, if one is missing you'd get nothing. IMO you need a third table, perhaps called ALPHABET, containing all possible letters:
CREATE TABLE ALPHABET (LETTER CHAR(1));
and populated with 'A', 'B', 'C', etc. In this case your join would become:
SELECT a.LETTER,
t1.VALUE,
t2.NUM
FROM ALPHABET a
FULL OUTER JOIN TABLE_1 t1
ON t1.LETTER = a.LETTER
FULL OUTER JOIN TABLE_2 t2
ON t2.LETTER = a.LETTER
which, if ALPHABET is only populated with ('A, 'B', 'C', and 'D'), produces
LETTER VALUE NUM
A 2 1
B 5 (null)
C (null) 7
D (null) (null)
SQLFiddle here (and note that in the fiddle I changed the variable name NUMBER to NUM to eliminate the need to double-quote it everywhere it's used).
There are two tables table1 and table2.
Table1 is as below:
col1 | col2 | Col3
A 10 X
B 11 X
C 10 X
A 20 X
Table2 is as below:
col1 | col2 | col3 | col4
A 10 1 UDHAY
B 11 2 VIJAY
C 10 1 SURESH
A 20 2 ARUL
A 10 3 UDHAY
B 11 4 VIJAY
C 10 4 SURESH
A 20 5 ARUL
I want to display the column col4 in table2 with 3 join conditions as below.
table1.COl1 = table2.COl1
and table1.COl2 = table2.COl2
and table2.COl3 = '1'
Sample query :
select
table2.col4
from table1
left outer join table2
on(
table1.COl1 = table2.COl1
and table1.COl2 = table2.COl2
and table2.COl3 = '1');
Question: IF I want to display table2.col4 for condition table2.col3 1,2,3,4,5 with matching other condition from table1, how to make the script?
Actually I know we can add same table 5 times with different alias names and can print. But I don't want to repeat the same condition 5 times. Only the where conditions should be common for all 5 values.
Added on 30-OCT-2013:
Thanks for your response. NO not like you mentioned by using IN. Right now I am using below script concept :
select A.col1,A.co2,B1.col4 ,B2.col4,B3.col4.B4.col4
from table1 A
left outer join table2 B1
on(
A.COl1 = B1.COl1
and A.COl2 = B1.COl2
and B1.COl3 = '1')
left outer join table2 B2
on(
A.COl1 = B2.COl1
and A.COl2 = B2.COl2
and B2.COl3 = '2')
left outer join table2 B3
on(
A.COl1 = B3.COl1
and A.COl2 = B3.COl2
and B3.COl3 = '3')
left outer join table2 B4
on(
A.COl1 = B4.COl1
and A.COl2 = B4.COl2
and B4.COl3 = '4');
So my output will be:
A | 10 | UDHAY | |UDHAY| |
B | 11 | | VIJAY| | VIJAY |
C | 10 | SURESH | | | SURESH |
A | 20 | | ARUL | | |
But like above script I have to make it for 25 combination (1 to 25). So if I make the script like above the script lines will be more than 200 lines. To avoid that will you please help to suggest some other method to reduce the script lines and get the same output?
I'm not sure I'm getting you correctly, do you mean something like this?
and table2.COl3 IN ('1','2','3','4','5')
First solution (trivial):
Make a view with the whole set of Joins and query for it instead on your script, it's a bit dodgy but gets your script to be shorter. If your data set ends up growing off the scales you could switch to a materialized view instead and simplify what could end up being a costly plan.
Second solution (not so trivial):
If your tables do have a name convention you could write a PL block and loop through it, going around and arraying the tables that you want to join so that you can concat the joins on runtime in a string and run it as dynamic SQL.
I've simplified this example but hopefully the example provides enough substance to make sense.
If I have a table such as the following...
ITEM GROUP
---- -----
A 1
B 1
C 1
D 2
E 2
F 3
G 4
... and I am provided items A, B, D and F, I would like to contruct a query that will return those details along with the additional items in the associated groups, C and E.
It seems that I should be able to do some sort of inner join but I'm not clear on how it could be done. It would be best if this were done in a single query due to the constraints of the environment.
Thanks much!
If I understand you correctly, this would work.
SELECT item,
group_num
FROM table_name
WHERE grroup_num IN (SELECT group_num
FROM table_name
WHERE item IN ('A', 'B', 'D', 'F'))
You could also write it as an EXISTS
SELECT item,
group_num
FROM table_name a
WHERE EXISTS( SELECT 1
FROM table_name b
WHERE a.group_num = b.group_num
AND b.item IN ('A','B','D','F') )