SQL Join with two ON clauses (Nested Join?) - sql

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.

Related

How to replace an OR statement from a join in sql server

I have the following query that uses an or statement on a join, so basically if one condition on the join isn't met it must check the next condition. The problem is that with the OR statement it takes really long to run but when I remove one of the OR conditions it runs instantly. is there a better way to do this with both conditions without using the OR statement so it would speed up the query
select t5.TransactionNumber
,t4.ID
,t3.[Entry] AS Amount
,t2.Address AS AddressDetail
,t1.PhoneNumber AS ContactNumber
FROM Table1 t1 (NOLOCK)
JOIN Table2 t2 (NOLOCK) ON t2.FicaID = t1.FicaId
inner join Table3 t3 (NOLOCK) ON (t3.ID = t2.ID AND t3.Code = t2.Code) or (t3.TypeID = t2.TypeID) //on this join i have an or statement if one condition isnt met it must check the next condition
LEFT JOIN Table4 t4 (NOLOCK) ON t4.Result = t3.Result
LEFT JOIN Table5 t5 (NOLOCK) ON t5.AccNum = t3.AccNum
where t1.date>'2018-09-01' and t1.date<'2018-09-30'
By the rule of distributivity in logic,
P OR (Q AND R) can be written as
(P OR Q) AND (P OR R).. maybe that helps?
You could try by using left join and COALESCE function
select t5.TransactionNumber
,t4.ID
,COALESCE(t3.[Entry],t33.[Entry]) AS Amount
,t2.Address AS AddressDetail
,t1.PhoneNumber AS ContactNumber
FROM Table1 t1 (NOLOCK)
JOIN Table2 t2 (NOLOCK) ON t2.FicaID = t1.FicaId
left join Table3 t3 (NOLOCK) ON (t3.ID = t2.ID AND t3.Code = t2.Code)
left join Table3 t33 (t33.TypeID = t2.TypeID) //I moved it to left join
LEFT JOIN Table4 t4 (NOLOCK) ON t4.Result = t3.Result
LEFT JOIN Table5 t5 (NOLOCK) ON t5.AccNum = t3.AccNum
where t1.date>'2018-09-01' and t1.date<'2018-09-30'
You can try below query :
select * from
(
select t5.TransactionNumber
,t4.ID
,t3.[Entry] AS Amount
,t2.Address AS AddressDetail
,t1.PhoneNumber AS ContactNumber
FROM Table1 t1 (NOLOCK)
JOIN Table2 t2 (NOLOCK) ON t2.FicaID = t1.FicaId
inner join Table3 t3 (NOLOCK) ON (t3.ID = t2.ID AND t3.Code = t2.Code)
)A
join Table3 t3 (NOLOCK) ON (A.TypeID = t3.TypeID)
LEFT JOIN Table4 t4 (NOLOCK) ON t4.Result = t3.Result
LEFT JOIN Table5 t5 (NOLOCK) ON t5.AccNum = t3.AccNum
where t1.date>'2018-09-01' and t1.date<'2018-09-30'

Joining tbl1 to select statement twice with join to tbl2 that also joins to tbl3

I'm using SQL server manger.
I have 3 tables
I need a query that pulls t1 ands add an Origin Basin and a Destination Basin.
So far I have the following:
select T1.[Country (destination)], T3.AreaName
From T1
left outer join T2 on
T1.[Country (destination)] = T2.CountryName
inner join T3 on
T2.AreaID = T3.AreaID
inner join T3 on
T2.AreaID = T3.AreaID
Which returns:
Country | Area
However, I'm having trouble doing this for the second country column. I believe you use aliases. I've tried:
select (select AreaName
FROM T3
where T3.AreaID = T2.AreaID) as 'Area Imp',
(select AreaID
From T2
where T2.CountryName = T1.[Country (origin)]) as 'x',
(select AreaID
From T2
where T2.CountryName = T1.[Country (destination)]) as 'y'
FROM T1
But I can't get it to work.
This is what you need to do:
select t1.date, t1.country_destination, t1.country_origin, destination_area.AreaName as area_destination, origin_area.AreaName as area_origin
from t1 as t1 join t2 as destination on t1.country_destination = destination.countryname
join t2 as origin on t1.country_origin = origin.countryname
join t3 as destination_area on t2.areaid = destination_area.areaid
join t3 as origin_area on t2.areaid = origin_area.areaid
You will need to join with the same table twice, both for t2 and t3 so that you get the matching records for your needs.
It helps usually to put aliases that match the purpose of the join (in this case, destination and origin) when writing the query.
I think what you're trying to do is something like this:
select T1.*, T3dest.AreaName, T3orig.AreaName
From
T1
inner join
T2 T2dest on
T1.[Country (destination)] = T2dest.CountryName
inner join
T3 T3dest on
T2dest.AreaID = T3dest.AreaID
inner join
T2 T2orig on
T1.[Country (origin)] = T2orig.CountryName
inner join
T3 T3orig on
T2orig.AreaID = T3orig.AreaID
Note that I've switched to inner joins throughout, at the moment. If you do want left join semantics, you either need to use those for all of the joins to the T2 and T3 tables or you need to change the join order (so that the relevant T3 joins to the T2 tables occur before the attempted join with T1). It's not clear from the sample data if that's required, however.
Try this, You would still want to join on area id's
select T1.Date,T1.[Country (destination)], null [Country (origin)], T3.AreaName [AreaName(Destination)], null [AreaName(Origin)]
From T1
left outer join T2 on
T1.[Country (destination)] = T2.CountryName
inner join T3 on
T2.AreaID = T3.AreaID
union all
select T1.Date,null [Country (destination)], t1.[Country (origin)], Null [AreaName(Destination)], t3. [AreaName(Origin)]
From T1
left outer join T2 on
T1.[Country (Origin)] = T2.CountryName
inner join T3 on
T2.AreaID = T3.AreaID

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 ... ;

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)

SQL - Difference between these Joins?

I should probably know this by now, but what, if any is the difference between the two statements below?
The nested join:
SELECT
t1.*
FROM
table1 t1
INNER JOIN table2 t2
LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
ON t2.table2_ID = t1.table1_ID
The more traditional join:
SELECT
t1.*
FROM
table1 t1
INNER JOIN table2 t2 ON t2.table2_ID = t1.table1_ID
LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
Well, it's the order of operations..
SELECT
t1.*
FROM
table1 t1
INNER JOIN table2 t2
LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
ON t2.table2_ID = t1.table1_ID
could be rewritten as:
SELECT
t1.*
FROM
table1 t1 -- inner join t1
INNER JOIN
(table2 t2 LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID) -- with this
ON t2.table2_ID = t1.table1_ID -- on this condition
So basically, first you LEFT JOIN t2 with t3, based on the join condition: table3_ID = table2_ID, then you INNER JOIN t1 with t2 on table2_ID = table1_ID.
In your second example you first INNER JOIN t1 with t2, and then LEFT JOIN the resulting inner join with table t3 on the condition table2_ID = table1_ID.
SELECT
t1.*
FROM
table1 t1
INNER JOIN table2 t2 ON t2.table2_ID = t1.table1_ID
LEFT JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
could be rewritten as:
SELECT
t1.*
FROM
(table1 t1 INNER JOIN table2 t2 ON t2.table2_ID = t1.table1_ID) -- first inner join
LEFT JOIN -- then left join
table3 t3 ON t3.table3_ID = t2.table2_ID -- the result with this
EDIT
I apologize. My first remark was wrong. The two queries will produce the same results but there may be a difference in performance as the first query may perform slower than the second query in some instances ( when table 1 contains only a subset of the elements in table 2) as the LEFT JOIN will be executed first - and only then intersected with table1. As opposed to the second query which allows the query optimizer to do it's job.
For your specific example, I don't think there should be any difference in the query plans generated, but there's definitely a difference in readability. Your 2nd example is MUCH easier to follow.
If you were to reverse the types of joins in the example, you could end up with much different results.
SELECT t1.*
FROM table1 t1
LEFT JOIN table2 t2 ON t2.table2_ID = t1.table1_ID
INNER JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
-- may not produce the same results as...
SELECT t1.*
FROM table1 t1
LEFT JOIN table2 t2
INNER JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
ON t2.table2_ID = t1.table1_ID
Based on the fact that order of the joins DOES matter in many cases - careful thought should go into how you're writing your join syntax. If you find that the 2nd example is what you're really trying to accomplish, i'd consider rewriting the query so that you can put more emphasis on the order of your joins...
SELECT t1.*
FROM table2 t2
INNER JOIN table3 t3 ON t3.table3_ID = t2.table2_ID
RIGHT JOIN table1 t1 ON t2.table2_ID = t1.table1_ID
The best way to see what is different in these two queries is to compare the Query Plan for both these queries.
There is no difference in the result sets for these IF there are always rows in table3 for a given row in table2.
I tried it on my database and the difference in the query plans was that
1. For the first query, the optimizer chose to do the join on table2 and table 3 first.
2. For the second query, the optimizer chose to join table1 and table2 first.
You should see no difference at all between the two queries, provided your DBMS' optimizer is up to scratch. That, however, even for big-iron, high-cost platforms, is not an assumption I'd be confident in making, so I'd be fairly unsurprised to discover that query plans (and consequently execution times) varied.