I am trying to join 7 tables in a select query four with inner join and two with outer join.
Can I combine outer and inner join in the same query? Because when I am doing so i am not getting proper results. I tried with both ANSI joins ( INNER JOIN , LEFT OUTER JOIN) and with + sign as well. I am wondering is the order of joining is important in ANSI joins?
so here is the scenario,
table a
table b
table c
table e
table f
tanle g
table h
inner join ( a , b, c )
inner join ( a , e , f)
left outer outer join ( f , g)
left outer join ( f , h)
My query ( which looks wrong) _==>
FROM a inner join b on (a.col_1 = b.col_1)
inner join c on (b.y = c.y)
inner join e on ( a.col_1 = e.col_1)
inner join f on (e.col_4 = f.col_4)
left outer join g on (g.col_5= f.col_5)
left outer join h on (h.col_6 = f.col_6)
Could any one please help me with the correct joining query?
Any lead would be highly appreciated
You can always write a query with INNER and OUTER JOIN together.
Your example is not clear because is very important, when you write a query knows your goal.
INNER JOIN: You use this operation when you want to extract rows across two (or more) tables, and for you is important the presence of those data values in both tables.
OUTER JOIN: You use this operation when you want to extract rows from a main table independent if the corresponding row is presents in linked table.
I try to make an example:
I have a table (PERSON) with a list of persons. This table has a foreign key to point a table (COUNTRY) to know information about birth place. I have another table (BANK_ACCOUNT) where I store the bank account for every person (if a person has).
My result wants to know: all person information (included the birth place name) and if a person has a bank account, knows it.
The query:
SELECT p.*, b.name, b.account_no
FROM person p
INNER JOIN country c <-- Here I apply an INNER JOIN
ON p.fk_country = c.id
LEFT OUTER JOIN bank_account b <-- Here I apply an OUTER JOIN
ON b.fk_person = p.id
In this case is very important to know the goal! About another goal the upper query can be wrong.
About the order of JOIN: Is not important the order but the type yes.
INNER JOIN: Is commutative. If you have table A and table B if you write
A INNER JOIN B is the same if you write B INNER JOIN A
OUTER JOIN: Is not commutative. If you have table A and table B the follows queries are differences:
A LEFT OUTER JOIN B
B LEFT OUTER JOIN A
Because the first tells: Get all A rows and if there exists a corresponding row in B give me those information, instead return NULL value.
The second query tells: get all B rows and if there exists a corresponding row in A give me those information, instead return NULL value.
Some of your INNER JOINs (="requirements") probably aren't returning anything.
Inner join returns nothing from the source table (a) if the "join on -condition" can't be fullfilled. Left join returns rows (from table a) and fills the joined row's columns with nulls if not found. In both cases, if there are multiple matches, multiple rows are also returned.
Example with one row in each table:
table A values (col_1, ..., col_4) = (1, 2, 3, 4)
table b values (col_1, x, y, z) = (1, 3, 5, 7)
table c values (col_1, x, y, z) = (1, 3, 5, 7)
table e values (col_1, ..., col_4) = (1, ..., 6)
table f values (col_1, ..., col_6) = (8, ..., 7, 4, 3)
table g values (col_1, ..., col_6) = (7, ..., 4, 6)
table h values (col_1, ..., col_6) = (..., 9)
And our query:
FROM a
inner join b on (a.col_1 = b.col_1) -- requirement 1
inner join c on (b.y = c.y) -- requirement 2
inner join e on ( a.col_1 = e.col_1) -- requirement 3
inner join f on (e.col_4 = f.col_4) -- requirement 4
left outer join g on (g.col_5= f.col_5) -- optional 1
left outer join h on (h.col_6 = f.col_6) -- optional 2
So do we return anything?
Requirement 1: a.col_1 = b.col_1; 1 = 1 --> OK
Requirement 2: b.y = c.y; 5 = 5 -- > OK
Requirement 3: a.col_1 = e.col_1; 1 = 1 -> OK
Requirement 4: e.col_4 = f.col_4; 6 != 7 -> NOT OK
Already at this point the query won't return anything and we don't event need to check left joins (there's nothing to join on).
If f.col4 would have been 6 instead of 7, the example row would be returned. Then we would also join the row(s) from g if the condition can be matched (g.col_5= f.col_5; 4 = 4 -> OK). In this example, selected colums from table h would all have value null, because the condition (optional 2) isn't met.
I hope this helps you finding the issues. It's really hard to see the actual problem without valid data. In the future, consider using for example SQL Fiddle with your questions.
PS. OUTER and INNER are optional words and don't make any difference in the query. So LEFT OUTER JOIN is same as LEFT JOIN and INNER JOIN is same as JOIN.
Related
The query returns duplicates on columns when adding the third table to the query
TABLE A
A.AccId
A.AccNr
A.EntId
TABLE B
B.EntName
B.EntId
TABLE C
C.AccNr
C.CustomerNr
SELECT A.AccID, A.AccNr, A.EntId, B.EntName, B.EntId, C.AccNr,C.CustomerNr, C.EntName
FROM ((Cat.dbo.A
INNER JOIN Cat.dbo.B ON A.EntId = B.EntId)
INNER JOIN Dog.dbo.C ON B.EntName = C.EntName
Your query needs to be updated first. I dont see EntName column in Table C.
There is a possibility of duplicates, if there are many rows matching in Table C , rows from Table A & Table B are repeated while joining with Table C.
If there are many records matching for EntName in C, then you will have duplicates. if you don't want duplicate, you have to apply DISTINCT
SELECT DISTINCT A.AccID, A.AccNr, A.EntId, B.EntName, B.EntId, C.AccNr,C.CustomerNr
FROM Cat.dbo.Accounts
INNER JOIN Cat.dbo.B ON A.EntId = B.EntId
INNER JOIN Dog.dbo.C ON B.EntName = C.EntName
Or if duplicates are due to duplicate records in Table C, you can filter them out before JOIN.
SELECT A.AccID, A.AccNr, A.EntId, B.EntName, B.EntId, C.AccNr,C.CustomerNr
FROM Cat.dbo.Accounts
INNER JOIN Cat.dbo.B ON A.EntId = B.EntId
INNER JOIN (SELECT DISTINCT CustomerNr, EntName FROM Dog.dbo.C) AS C ON B.EntName = C.EntName;
I need to join at least 4 tables. Table A is an Association table that contains a guid for Table B and C, Parentguid (B), Childguid (C). Table D contains information just for table C.
I need the results to look like this.
B - C - D
Monitor - Computer Name - Active
So the main thing is to show all of B table, only C table that is connected to B, and only D table this is associated with C.
I suspect I will need sub joins ( ). I am still a novice, it makes sense in my head but I can't seem to make the code work. I have played with joins for the past 2 days.
FROM vHWDesktopMonitor mon -- [Symantec_CMDB2].[dbo].[ResourceAssociation]
join ResourceAssociation RM on mon._ResourceGuid = RM.ParentResourceGuid
full outer join vComputer comp on RM.ChildResourceGuid = comp.Guid
full outer join vAsset on RM.ChildResourceGuid = vAsset._ResourceGuid
FROM vHWDesktopMonitor A
FULL OUTER JOIN ResourceAssociation B
on A._ResourceGuid = B.ParentResourceGuid
LEFT JOIN vComputer C
on B.ChildResourceGuid = C.Guid
LEFT JOIN vAsset D
on C.ChildResourceGuid = D._ResourceGuid
So the above will return
All FROM A and ALL records from B (Full Outer between A, B)
Only records from C that are in B (LEFT Between B and C)
Only records from D that are in C (LEFT Between C and D)
However, if you apply any where clause limits, it could reduce records which otherwise would be kept due to the left or outer joins...
For example if A._ResourceGuid ='7' exists in A but isn't in B;
and you set where B._ResourceGuid ='7' then the A record would otherwise would be kept due to the full outer join would then be excluded (making the full outer join the same as an INNER JOIN)!
a Full outer would return data like this:
A B
7 7
2
3
if you add a where clause where B=7 then you may be expecting to get because of the full outer since you said return all records from both...
A B
7 7
2
But you would end up getting
A B
7 7
Because the where clause occurs AFTER the full outer and therefore reduces the A.2 record.
To compensate for this you either have to put teh limits on teh join before the full outer executes or handle it in a where clause (but this method is VERY messy and prone to error and performance issues)
So when using outer joins, you MUST put the limiting criteria on the JOIN itself like below..
FROM vHWDesktopMonitor A
FULL OUTER JOIN ResourceAssociation B
on A._ResourceGuid = B.ParentResourceGuid
and B._resourceGuid = '7'
LEFT JOIN vComputer C
on B.ChildResourceGuid = C.Guid
LEFT JOIN vAsset D
on C.ChildResourceGuid = D._ResourceGuid
You could also put it in the where clause but you must remember to account for all the outer joins on the table and include null values for the other (this is just messy and slow)
FROM vHWDesktopMonitor A
FULL OUTER JOIN ResourceAssociation B
on A._ResourceGuid = B.ParentResourceGuid
LEFT JOIN vComputer C
on B.ChildResourceGuid = C.Guid
LEFT JOIN vAsset D
on C.ChildResourceGuid = D._ResourceGuid
WHERE (A._ResourceGuid is null OR B.ParentResourceGuid ='7')
If I understand you correctly either of these should work"
FROM vHWDesktopMonitor mon -- [Symantec_CMDB2].[dbo].[ResourceAssociation]
left join ResourceAssociation RM on mon._ResourceGuid = RM.ParentResourceGuid
left join vComputer comp on RM.ChildResourceGuid = comp.Guid
left join vAsset on comp.Guid = vAsset._ResourceGuid
or
FROM vHWDesktopMonitor mon -- [Symantec_CMDB2].[dbo].[ResourceAssociation]
left join ResourceAssociation RM on mon._ResourceGuid = RM.ParentResourceGuid
left join (select [list fields here] from vComputer comp
join vAsset on comp.Guid = vAsset._ResourceGuid) comp2
on RM.ChildResourceGuid = comp2.Guid
this should get you all the records from vHWDesktopMonitor and teh asscoiated records from ResourceAssociation with nulls for any records in vHWDesktopMonitor but not in ResourceAssociation. Then you get al teh records in vComputer that are also in ResourceAssociation. Finally you get al teh records in vAsset that are in vComputer. as alawys when you are getting all the records in teh first table, tehere will be nulls inteh fileds from other tables if you do not have an associated record.
If this doesn't work, perhaps you need to show us some sample data and expected results.
I have the following tables with the following attributes:
Op(OpNo, OpName, Date)
OpConvert(OpNo, M_OpNo, Source_ID, Date)
Source(Source_ID, Source_Name, Date)
Fleet(OpNo, S_No, Date)
I have the current multiple JOIN query which gives me the results that I want:
SELECT O.OpNo AS Op_NO, O.OpName, O.Date AS Date_Entered, C.*
FROM Op O
LEFT OUTER JOIN OpConvert C
ON O.OpNo = C.OpNo
LEFT OUTER JOIN Source D
ON C.Source_ID = D.Source_ID
WHERE C.OpNo IS NOT NULL
The problem is this. I need to join the Fleet table on the previous multiple JOIN statement to attach the relevant S_No to the multiple JOIN table. Would I still be able to accomplish this using a LEFT OUTER JOIN or would I have to use a different JOIN statement? Also, which table would I JOIN on?
Please note that I am only familiar with LEFT OUTER JOINS.
Thanks.
I guess in your case you could use INNER JOIN or LEFT JOIN (which is the same thing as LEFT OUTER JOIN in SQL Server.
INNER JOIN means that it will only return records from other tables only if there are corresponding records (based on the join condition) in the Fleet table.
LEFT JOIN means that it will return records from other tables even if there are no corresponding records (based on the join condition) in the Fleet table. All columns from Fleet will return NULL in this case.
As for which table to join, you should really join the table that makes more logical sense based on your data structure.
Yes, you can use all tables mentioned before in your join conditions. Actually, JOINS (no matter of INNER, LEFT OUTER, RIGHT OUTER, CROSS, FULL OUTER or whatever) are left- associative, i. e. they are implicitly evaluated as if they would have been included in parentheses from the left as follows:
FROM ( ( ( Op O
LEFT OUTER JOIN OpConvert C
ON O.OpNo = C.OpNo
)
LEFT OUTER JOIN Source D
ON C.Source_ID = D.Source_ID
)
LEFT OUTER JOIN Fleet
ON ...
)
This is similar to how + or - would implicitly use parentheses, i. e.
2 + 3 - 4 - 5
is evaluated as
(((2 + 3) - 4) - 5)
By the way: If you use C.OpNo IS NOT NULL, then the LEFT OUTER JOIN Source D is treated as if it were an INNER JOIN, as you are explicitly removing all the "OUTER" rows.
this is the original SQL, that works very well.
select a.sessionid
from session a
left
outer
join applicationinfo b
on a.sessionid=b.sessionid
left
outer
join license c
on a.sessionid=c.sessionid
limit 10
;
below is the converted SQL
SELECT s.sessionid
FROM
( SELECT *
FROM session a
LEFT
OUTER
JOIN applicationinfo b
ON (a.sessionid = b.sessionid)
)s
LEFT
OUTER
JOIN license c
ON (s.sessionid = c.sessionid)
limit 10
;
the second SQL will get 10 NULLs. Since those tables are left joined on the sessionid field. Suppose in the second SQL the s.sessionid should not be NULL.
Could someone tell me the reason why those two SQL cannot return the same result. Thanks.
I have three tables: R, S and P.
Table R Joins with S through a foreign key; there should be at least one record in S, so I can JOIN:
SELECT
*
FROM
R
JOIN S ON (S.id = R.fks)
If there's no record in S then I get no rows, that's fine.
Then table S joins with P, where records is P may or may not be present and joined with S.
So I do
SELECT
*
FROM
R
JOIN S ON (S.id = R.fks)
LEFT JOIN P ON (P.id = S.fkp)
What if I wanted the second JOIN to be tied to S not to R, like if I could use parentheses:
SELECT
*
FROM
R
JOIN (S ON (S.id = R.fks) JOIN P ON (P.id = S.fkp))
Or is that already a natural behaviour of the cartesian product between R, S and P?
All kinds of outer and normal joins are in the same precedence class and operators take effect left-to-right at a given nesting level of the query. You can put the join expression on the right side in parentheses to cause it to take effect first. Remember that you will have to move the ON clauses around so that they stay with their joins—the join in parentheses takes its ON clause with it into the parentheses, so it now comes textually before the other ON clause which will be after the parentheses in the outer join statement.
(PostgreSQL example)
In
SELECT * FROM a LEFT JOIN b ON (a.id = b.id) JOIN c ON (b.ref = c.id);
the a-b join takes effect first, but we can force the b-c join to take effect first by putting it in parentheses, which looks like:
SELECT * FROM a LEFT JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
Often you can express the same thing without extra parentheses by moving the joins around and changing the direction of the outer joins, e.g.
SELECT * FROM b JOIN c ON (b.ref = c.id) RIGHT JOIN a ON (a.id = b.id);
When you join the third table, your first query
SELECT
*
FROM
R
JOIN S ON (S.id = R.fks)
is like a derived table to which you're joining the third table. So if R JOIN S produces no rows, then joining P will never yield any rows (because you're trying to join to an empty table).
So, if you're looking for precedence rules then in this case it's just set by using LEFT JOIN as opposed to JOIN.
However, I may be misunderstanding your question, because if I were writing the query, I would swap S and R around. eg.
SELECT
*
FROM
S
JOIN R ON (S.id = R.fks)
The second join is tied to S as you explicity state JOIN P ON (P.id = S.fkp) - no column from R is referenced in the join.
with a as (select 1 as test union select 2)
select * from a left join
a as b on a.test=b.test and b.test=1 inner join
a as c on b.test=c.test
go
with a as (select 1 as test union select 2)
select * from a inner join
a as b on a.test=b.test right join
a as c on b.test=c.test and b.test=1
Ideally, we would hope that the above two queries are the same. However, they are not - so anybody that says a right join can be replaced with a left join in all cases is wrong. Only by using the right join can we get the required result.