is there a way to do multiple left outer joins in oracle? - sql

Why won't this work in Oracle?
Is there a way to make this work?
FROM table1 a,
table2 b,
table3 c
WHERE a.some_id = '10'
AND a.other_id (+)= b.other_id
AND a.other_id (+)= c.other_id
I want table1 to be left outer joined on multiple tables...
If I try to change it to use an ANSI join, I get compilation errors. I did the following:
FROM table2 b, table3 c
LEFT JOIN table1 a ON a.other_id = b.other_id and a.other_id = c.other_id

OK, looking at the examples from the Oracle docs, my recollection of the syntax was correct, so I'm turning my comment into an answer. Assuming that your goal is a left outer join where A is the base table, and you join matching rows from B and C, rewrite your query as follows (note that I'm just changing the prefixes; I like to have the source rowset on the right).
FROM table1 a,
table2 b,
table3 c
WHERE a.some_id = '10'
AND b.other_id (+)= a.other_id
AND c.other_id (+)= a.other_id
If that's not what you're trying to do, then the query is borked: you're doing a cartesian join of B and C, and then attempting an outer join from that partial result to A, with an additional predicate on A. Which doesn't make a lot of sense.

use ansi joins. They are way clearer IMO. BUt for some reason they don't work with materialized views...

You can do something like this.
FROM table1 a, table2 b, table3 c
WHERE a.some_id = '10'
AND a.other_id = b.other_id(+)
AND a.other_id = c.other_id(+)

I wanted to address separately this part of your question:
If I try to change it to ANSI join I get compilation errors. I did the following:
FROM table2 b, table3 c
LEFT JOIN table1 a ON a.other_id = b.other_id and a.other_id = c.other_id
In an ANSI join, at least in Oracle, you are operating on exactly two row sources. The LEFT JOIN operator in your example has table3 and table1 as its operands; so you cannot reference "b.otherid" in the ON clause. You need a new join operator for each additional table.
I believe what you are trying to do is outer join table 2 and table 3 to table 1. So what you should be doing is this:
FROM table1 a LEFT JOIN table2 b ON b.other_id = a.other_id
LEFT JOIN table3 c ON c.other_id = a.other_id
or Henry Gao's query if you want to use Oracle-specific syntax.

In oracle you cannot outer join the same table to more than one other table. You can create views that have joins in them, then join to that view. As side note, you also cannot outer join to an sub select, so that is not an option here either.

You could off course try the following (Table b and c being the BASE)
FROM (SELECT other_id FROM table2
UNION
SELECT other_id FROM table3) b
LEFT JOIN table1 a b.other_id = a.other_id
But then again I am an Oracle Nono

Related

Re-Writing a SQL Statement with a Subquery to Have a Join

I have to re-write a SQL statement with a subquery so that it has a join for my job. So far, this is what I have.
SELECT * FROM Table_A
WHERE TABLE_A.A_ID NOT IN
(SELECT LK.A_ID FROM Link_Table LK
LEFT JOIN Table_B B
ON B.B_ID = LK.B_ID)
I am really having a hard time with this. I feel like this is because of the link tables though. Can anyone give me advice on altering this query?
Seems like you want a LEFT JOin with a IS NULL in the where:
SELECT {Column list} --Don't use *
FROM dbo.Table_A A
LEFT JOIN dbo.Link_Table LK ON A.A_ID = LK.A_ID
WHERE LK.A_ID IS NULL;
You don't need the reference to Table_B at all here.
Personally, however, I would prefer an EXISTS, but that is a subquery again:
SELECT {Column List}
FROM dbo.Table_A A
WHERE NOT EXISTS (SELECT 1
FROM dbo.Link_Table LK
WHERE A.A_ID = LK.A_ID);

What's the SQL Equivalent of the SPSS Partial Outer Join?

I'm working on a project to convert an old SPSS system to Oracle. The current code makes heavy use of partial outer joins, and I'm not sure what the best way to replicate that in SQL would be.
Here's an example of a typical query:
SELECT
TA.A
TB.B
TC.C
FROM
TABLE_A TA
TABLE_B TB
TABLE_C TC
PARTIAL OUTER JOIN
TA.FIELD = TB.FIELD
AND TB.FIELD = TC.FIELD
From what I've read in the IBM Knowledge Base, a partial outer join is essentially a left/right outer join that merges multiple tables. IBM provides the following Venn diagram:
It seems like the best way to replicate this would be to do a full outer join between tables A and C, and then left outer joins from A to C and B to C.
Is that correct? Is there a better solution?
Thanks!
I asked around the office and one of the senior devs pointed me to this manual which defines a partial outer join as
Returns all records from the primary file (first file
in the FROM clause) whether or not there is a match in the secondary file(s)
In other words, take the first table in the FROM clause and do a left outer join to all the other tables.
So the original query:
SELECT
TA.A
TB.B
TC.C
FROM
TABLE_A TA
TABLE_B TB
TABLE_C TC
PARTIAL OUTER JOIN
TA.FIELD = TB.FIELD
AND TB.FIELD = TC.FIELD
Should become this:
SELECT
TA.A
TB.B
TC.C
FROM
TABLE_A TA LEFT OUTER JOIN TABLE_B TB ON TA.FIELD = TB.FIELD
LEFT OUTER JOIN TABLE_C TC ON TA.FIELD = TC.FIELD
You can do this in SQL using:
SELECT
TA.A,
TB.B,
TC.B
FROM
TABLE_A TA
FULL OUTER JOIN
TABLE_B TB
ON (TA.FIELD = TB.FIELD)
LEFT OUTER JOIN
TABLE_C TC
ON (TA.FIELD = TC.FIELD)
OR (TB.FIELD = TC.FIELD);
Every record in tables A and B will return, even if they do not match. Then only records from table C that match one in A or B will return.
The documentation is not at all clear. I'm not sure what SPSS does when there are rows in A and B that match different rows in C. One possibility is
select a.a, b.b, c.c
from a full join
b
on a.? = b.? left join
c
on a.? = c.? or b.? = c.?;

How to use UNION of more than one table in JOIN clause

I need union more than one table in a select's join clause,given below is a sample
select .. ...
from table_a inner join (/*here i want to join two tables(ex. table_c and table_b)*/ ) -- not i am using left join also which is in another condition
where /*some condtitions*/
how this is possible ?
Do you mean that you want to do this?
select ...
from table_a join
(select ... from table_b
union
select ... from table_c) t on table_a.col = t.col
That sort of thing?
JOIN is a binary operator, so you may join two tables or views at a time. In order to join three tables, you can join two of them and then join the result with the third one.
It's like addition: to sum up three numbers, you add the second to the first, and then add the third to the result.
select * from
table_a a
inner join
table_b b on a.id= b.id
inner join
table_c c on b.id= c.id
where /*some conditions*/;

Changing the ON condition order results in different query results?

Will there be any difference if I change the order from this to the next one in the last line ESPECIALLY when I use left join or left outer join? SOme people confuse me that it might have differnet value when we change order, I reckon they themselves aren't sure about this.
Or, if we change the order, under what situations such as right outer, right, left, left outer joins the query result differs?
It makes no difference which side you put criteria on when an = is being used.
Table order matters in the case of LEFT JOIN and RIGHT JOIN, but criteria order does not.
For example:
SELECT *
FROM Table1 a
LEFT JOIN Table2 b
ON a.ID = b.ID
Is equivalent to:
SELECT *
FROM Table2 a
RIGHT JOIN Table1 b
ON a.ID = b.ID
But not equivalent to:
SELECT *
FROM Table2 a
LEFT JOIN Table1 b
ON a.ID = b.ID
Demo: SQL Fiddle

How to use oracle outer join with a filter where clause

If i write a sql:
select *
from a,b
where a.id=b.id(+)
and b.val="test"
and i want all records from a where corresponding record in b does not exist or it exists with val="test", is this the correct query?
You're much better off using the ANSI syntax
SELECT *
FROM a
LEFT OUTER JOIN b ON( a.id = b.id and
b.val = 'test' )
You can do the same thing using Oracle's syntax as well but it gets a bit hinkey
SELECT *
FROM a,
b
WHERE a.id = b.id(+)
AND b.val(+) = 'test'
Note that in both cases, I'm ignoring the c table since you don't specify a join condition. And I'm assuming that you don't really want to join A to B and then generate a Cartesian product with C.
Move the condition into the JOIN clause and use the ANSI standard join pattern.
SELECT NameYourFields,...
FROM A
LEFT OUTER JOIN B
ON A.ID = B.ID
AND B.VAL = 'test'
INNER JOIN C
ON ...
A LEFT OUTER JOIN is one of the JOIN operations that allow you to specify a join clause. It preserves the unmatched rows from the first (left) table, joining them with a NULL row in the shape of the second (right) table.
So you can do as follows :
SELECT
FROM a LEFT OUTER JOIN b
ON a.id = b.id
--Note that you have used double quote "test" which is not used for varchar in SQL you should use single quote 'test'
AND b.val = 'test';
SELECT * FROM abc a, xyz b
WHERE a.id = b.id
AND b.val = 'test'