Oracle Left outer joins using old syntax - sql

So, I've been trying to do following outer joins:
SELECT * FROM table1
LEFT OUTER JOIN table2
ON table1.a = table2.a
AND table1.b = table2.b
LEFT OUTER JOIN table3
ON table1.a = table3.a
AND table1.b = table3.c
I've tested and could do it with no problems. However, the software I'm using uses the older syntax for left joins. And so I wrote it like this:
SELECT * FROM table1, table2, table3
WHERE table1.a = table2.a (+)
AND table1.b = table2.b (+)
AND table1.c = table3.a (+)
AND table2.c = table3.b (+)
Obviously, I get the ORA-01417: a table may be outer joined to at most one other table error. Any way to workaround this issue?
table1.c is not present in any table2 columns, so I'm forced to use the table1.c = table3.b clause.

Related

SQL Join with two ON clauses (Nested Join?)

I am debugging a report that has been created by someone else and it has the join criteria below. (I have laid out to my preference and anonymised the table names)
SELECT --columns
FROM Table1
JOIN Table2
JOIN Table3
ON Table2.pred = Table3.pred
JOIN Table4
ON Table2.pred = Table4.pred
JOIN Table5
ON Table2.pred = Table5.pred AND Table2.pred = Table5.pred AND Table3.pred = Table5.pred
JOIN Table6
ON Table3.pred = Table6.pred
ON Table1.pred = Table5.pred AND Table1.pred = Table5.pred
LEFT JOIN Table7
ON Table5.pred = Table7.pred AND Table5.pred = Table7.pred
LEFT JOIN Table7 AS Table7_1
ON Table5.pred = Table7_1.pred AND Table5.pred = Table7_1.pred
WHERE --conditions
What I find confusing is that there is no join that associates Table1 with Table 2 and there are two ON clauses after the join to table 6. Usually multiple tables are joined:
FROM Table
JOIN Table2
ON --criteria
JOIN Table3
ON --criteria
JOIN Table4
ON --criteria
--etc
The query works but as someone trying to work out what it is doing I am struggling as I have never seen the join syntax before.
is anyone able to explain the syntax to me?
That is valid syntax. Here is a simpler example:
from t1 join
t2 join
t3
on t2.? = t3.?
on t1.? = t2.?
If written with parentheses, it makes more sense:
from t1 join
(t2 join
t3
on t2.? = t3.?
) on t1.? = t2.?
Although allowed, I strongly discourage you from using this syntax. Rewrite the query so the joins and ons are interleaved.

Stuck on multiple Left Join and Inner Join

I've to make a query on Oracle and i'm a little bit stuck with it. In my TABLE1, I've 287 reccords so I want all informations from TABLE2 AND TABLE3 that egal with my 287 reccords (that's why I use Left Join). But I also want all reccords that match between TABLE2 and TABLE4, TABLE4 AND TABLE5 (That's why I use Inner Join).
But my query don't work and I don't know why. Someone can help me ?
My query :
SELECT distinct(TABLE1.NUM_SIN),
TABLE1.LIBELLE,
TABLE1.DATE_FRAIS,
TABLE2.CODE_SIN,
TABLE2.PKPR,
TABLE1.MT,
TABLE4.POSTBUD,
TABLE3.VEENG
FROM TABLE1
LEFT JOIN TABLE2
ON TABLE2.NUM_SIN = TABLE1 .NUM_SIN
INNER JOIN TABLE4
ON TABLE4.NUM_SIN = TABLE2.NUM_SIN
AND TABLE4.SCSO = TABLE2.SCSO
LEFT JOIN TABLE5
ON TABLE5.CDC = TABLE4.NO
AND TABLE5.CDEXE = TABLE4.CDEXE
AND TABLE5.SCSO = TABLE4.SCSO
LEFT JOIN TABLE3
ON TABLE3.CNCT = TABLE1.NUM_SIN
WHERE ... ;
A graph to understand :
Thx in advice !
I think the issue here is perhaps that you really don't want to use an inner join in your query, and perhaps that you don't know exactly what the difference is between an inner join and an outer join.
The inner join in your query will return ONLY the rows from TABLE4 that are a match in TABLE2. Joins are sequential and cumulative, so your remaining LEFT joins will have the reduced rowset on the left side of the join.
Thus, I believe you will want to use LEFT joins throughout your query, e.g.:
SELECT distinct(TABLE1.NUM_SIN),
TABLE1.LIBELLE,
TABLE1.DATE_FRAIS,
TABLE2.CODE_SIN,
TABLE2.PKPR,
TABLE1.MT,
TABLE4.POSTBUD,
TABLE3.VEENG
FROM TABLE1
LEFT JOIN TABLE2
ON TABLE2.NUM_SIN = TABLE1 .NUM_SIN
LEFT JOIN TABLE4
ON TABLE4.NUM_SIN = TABLE2.NUM_SIN
AND TABLE4.SCSO = TABLE2.SCSO
LEFT JOIN TABLE5
ON TABLE5.CDC = TABLE4.NO
AND TABLE5.CDEXE = TABLE4.CDEXE
AND TABLE5.SCSO = TABLE4.SCSO
LEFT JOIN TABLE3
ON TABLE3.CNCT = TABLE1.NUM_SIN
WHERE ... ;
Are you sure you don't want to left join to table4? The way it is written only values in TABLE4 would be allowed which would limit the results from table2 and table5.
NB - the image CDN is filtered here so I can't see the image.
SELECT --
FROM TABLE1
LEFT JOIN TABLE2 ON TABLE2.NUM_SIN = TABLE1 .NUM_SIN
LEFT JOIN TABLE3 ON TABLE3.CNCT = TABLE1.NUM_SIN
-- unless you want to reduce the number of table2 rows use left join here.
LEFT JOIN TABLE4 ON TABLE4.NUM_SIN = TABLE2.NUM_SIN AND TABLE4.SCSO = TABLE2.SCSO
LEFT JOIN TABLE5 ON TABLE5.CDC = TABLE4.NO
AND TABLE5.CDEXE = TABLE4.CDEXE
AND TABLE5.SCSO = TABLE4.SCSO
WHERE ... ;

Outer Join 3 Tables in Rails

I have 3 models. Table1 belongs to Table2, and Table2 belongs to Table3.
I want to get an ActiveRecord::Relation that includes all of the fields from all 3 tables, including nulls (outer joining to get all of Table1), with a WHERE clause on Table1 and an order by a column in Table3.
What I want in SQL is:
SELECT * FROM Table1 LEFT OUTER JOIN Table2 ON Table2.id = Table1.table2_id
LEFT OUTER JOIN Table3 ON Table3.id = Table2.table3_id
WHERE Table1.column1 = "example"
ORDER BY Table3.table3_column
However, I have been trying for hours now to do this in rails and getting nowhere. Is it possible?
#records = Table1.joins(:table2).joins(:table3).where(:column1 => "example").order("table3_column")
(For example), gets me nowhere because it is looking for an association between Table1 and Table3, which doesn't exist other than through Table2. I need to join once, then join on top of that. Not to mention that is an inner join. I've tried of the form:
#records = Table1.joins("LEFT OUTER JOIN Table2 ON Table2.id = Table1.table2_id LEFT OUTER JOIN Table3 ON Table3.id = Table2.table3_id")
But I get nil from that.
Thanks for any help with this.
Try find_by_sql
Table1.find_by_sql("SELECT * FROM Table1
LEFT OUTER JOIN Table2 ON Table2.id = Table1.table2_id
LEFT OUTER JOIN Table3 ON Table3.id = Table2.table3_id
WHERE Table1.column1 = "example"
ORDER BY Table3.table3_column")
refer find by sql

SQL query - filter primary keys

I am using microsoft sql server and my query is of the following format (table1 primary key is (A,B)):
Select table1.A, table1.B, table2.C, Table3.D
from table1
left outer join table2 on table1.A = table2.A
left outer join tabl3 on table1.B = table3.B
//Here comes the question
//Except (A,B) in ( select A,B from BadTable)
How could I do it nicely? I was thinking about finding the set of CORRECT keys using sth like (cannot use except - running sql server 2000)
Select A,B
from table1
not exists ( select A,B from bad table)
and then inner join that with the main query. What do you think?
Select table1.A, table1.B, table2.C, Table3.D
from table1 T1
left outer join table2 on table1.A = table2.A
left outer join tabl3 on table1.B = table3.B
where not exists (select 1 from badTable where A = T1.A and B = T1.B)
would be a good way
Select table1.A, table1.B, table2.C, Table3.D ,badtable.*
from table1
left join table2 on table1.A = table2.A
left join table3 on table1.B = table3.B
left join badtable on table1.a = badtable.a
and table1.b = badtable.b
where badtable.a is null

Rewrite left outer join involving multiple tables from Informix to Oracle

How do I write an Oracle query which is equivalent to the following Informix query?
select tab1.a,tab2.b,tab3.c,tab4.d
from table1 tab1,
table2 tab2 OUTER (table3 tab3,table4 tab4,table5 tab5)
where tab3.xya = tab4.xya
AND tab4.ss = tab1.ss
AND tab3.dd = tab5.dd
AND tab1.fg = tab2.fg
AND tab4.kk = tab5.kk
AND tab3.desc = "XYZ"
I tried:
select tab1.a,tab2.b,tab3.c,tab4.d
from table1 tab1,
table2 tab2 LEFT OUTER JOIN (table3 tab3,table4 tab4,table5 tab5)
where tab3.xya = tab4.xya
AND tab4.ss = tab1.ss
AND tab3.dd = tab5.dd
AND tab1.fg = tab2.fg
AND tab4.kk = tab5.kk
AND tab3.desc = "XYZ"
What is the correct syntax?
Write one table per join, like this:
select tab1.a,tab2.b,tab3.c,tab4.d
from
table1 tab1
inner join table2 tab2 on tab2.fg = tab1.fg
left join table3 tab3 on tab3.xxx = tab1.xxx and tab3.desc = "XYZ"
left join table4 tab4 on tab4.xya = tab3.xya and tab4.ss = tab3.ss
left join table5 tab5 on tab5.dd = tab3.dd and tab5.kk = tab4.kk
Note that while my query contains actual left join, your query apparently doesn't.
Since the conditions are in the where, your query should behave like inner joins. (Although I admit I don't know Informix, so maybe I'm wrong there).
The specfific Informix extension used in the question works a bit differently with regards to left joins. Apart from the exact syntax of the join itself, this is mainly in the fact that in Informix, you can specify a list of outer joined tables. These will be left outer joined, and the join conditions can be put in the where clause. Note that this is a specific extension to SQL. Informix also supports 'normal' left joins, but you can't combine the two in one query, it seems.
In Oracle this extension doesn't exist, and you can't put outer join conditions in the where clause, since the conditions will be executed regardless.
So look what happens when you move conditions to the where clause:
select tab1.a,tab2.b,tab3.c,tab4.d
from
table1 tab1
inner join table2 tab2 on tab2.fg = tab1.fg
left join table3 tab3 on tab3.xxx = tab1.xxx
left join table4 tab4 on tab4.xya = tab3.xya
left join table5 tab5 on tab5.dd = tab3.dd and tab5.kk = tab4.kk
where
tab3.desc = "XYZ" and
tab4.ss = tab3.ss
Now, only rows will be returned for which those two conditions are true. They cannot be true when no row is found, so if there is no matching row in table3 and/or table4, or if ss is null in either of the two, one of these conditions is going to return false, and no row is returned. This effectively changed your outer join to an inner join, and as such changes the behavior significantly.
PS: left join and left outer join are the same. It means that you optionally join the second table to the first (the left one). Rows are returned if there is only data in the 'left' part of the join. In Oracle you can also right [outer] join to make not the left, but the right table the leading table. And there is and even full [outer] join to return a row if there is data in either table.
I'm guessing that you want something like
SELECT tab1.a, tab2.b, tab3.c, tab4.d
FROM table1 tab1
JOIN table2 tab2 ON (tab1.fg = tab2.fg)
LEFT OUTER JOIN table4 tab4 ON (tab1.ss = tab4.ss)
LEFT OUTER JOIN table3 tab3 ON (tab4.xya = tab3.xya and tab3.desc = 'XYZ')
LEFT OUTER JOIN table5 tab5 on (tab4.kk = tab5.kk AND
tab3.dd = tab5.dd)