TSQL: How does this JOIN resolve? - sql

I am doing these joins:
from #lps_at_lines2 as l2
left join jobmatl as jm on l2.item = jm.item
inner join job as j on jm.job = j.job
and jm.suffix = j.suffix
I'm not sure how the join would resolve and the official documentation is like reading hieroglyphics to me.
My guess is that first #lps_at_lines2 gets LEFT JOIN'd to jobmatl and then somehow job gets INNER JOIN'd to jm afterwards. Is that correct?

In a FROM clause, JOINs are parsed left to right -- the reading order in English. So, the LEFT JOIN is processed (logically) before the INNER JOIN.
The INNER JOIN conditions include:
jm.job = j.job and jm.suffix = j.suffix
These refer to the second table of the LEFT JOIN. Because NULL values fail, the INNER JOIN is turning the preceding LEFT JOIN into an INNER JOIN. In other words, you should get the same results using INNER JOIN for both.
Note that you can adjust the prioritization by using parentheses, but your version of the query does not do this.
In general, when mixing inner joins and left joins, I start by including all the inner joins and then LEFT JOINing the additional tables.

Related

Duplicate results due to multiple left outer joins

My query is as below
select DISTINCT
wftransaction.PERSONID,
pr.PRNUM,
pr.DESCRIPTION,
pr.PR1,
prline.GLDEBITACCT,
wftransaction.TRANSDATE,
prstatus.CHANGEBY
prstatus.CHANGEDATE,
prstatus.STATUS,
prstatus.MEMO
from pr
left outer join wftransaction pr.PRID = wftransaction.ORNERID and wftransaction.OWNERTABLE ='PR'
left outer join prline on pr.PRNUM = prline.PRNUM
left outer join prstatus on pr.PRNUM= prstatus.PRNUM
The result given by my query has duplicate results.Please do help me eliminate the redundant/repeating outputs.
When I put distinct this is what happens, https://i.stack.imgur.com/I2jnN.jpg,
I should only see 2 outputs with the same "STATUS" i.e.(COMPOSING) or (APPR) since they have different "GLDEBITACCT", other than that, there should be no more duplicates.
This is the picture of my Code and Result Set
i think you should be using inner join because if left join where being used all data from table A will repeatedly shows as the table B has its foreign key, or might sometimes you are lacking of WHERE clauses it depends on your query, it will be more helpful to others if you can paste the whole query and their structures with expected results.
https://www.codeproject.com/kb/database/visual_sql_joins.aspx
Good idea will be to place a simple DISTINCT clause in the query
select DISTINCT
wftransaction.PERSONID,
pr.PRNUM,
pr.DESCRIPTION,
pr.PR1,
prline.GLDEBITACCT,
wftransaction.TRANSDATE,
prstatus.CHANGEBY
prstatus.CHANGEDATE,
prstatus.STATUS,
prstatus.MEMO
from pr
left outer join wftransaction pr.PRID = wftransaction.ORNERID and wftransaction.OWNERTABLE ='PR'
left outer join prline on pr.PRNUM = prline.PRNUM
left outer join prstatus on pr.PRNUM= prstatus.PRNUM

returned no of rows different on left join

i have two sql query in one of them i perform left outer join, both should return same no of records but returned no of rows are different in both the sql queries
select Txn.txnRecNo
from Txn
inner join Person on Txn.uwId = Person.personId
full outer join TxnInsured on Txn.txnRecNo = TxnInsured.txnRecNo
left join TxnAdditionalInsured on Txn.txnRecNo = TxnAdditionalInsured.txnRecNo
where Txn.visibleFlag=1
and Txn.workingCopy=1
returned 20 records
select Txn.txnRecNo
from Txn
inner join Person on Txn.uwId = Person.personId
full outer join TxnInsured on Txn.txnRecNo = TxnInsured.txnRecNo
where Txn.visibleFlag=1
and Txn.workingCopy=1
returned 15 records
I suspect that the TxnAdditionalInsured table have duplicate records. use distinct
select distinct Txn.txnRecNo
from Txn
inner join Person on Txn.uwId = Person.personId
full outer join TxnInsured on Txn.txnRecNo = TxnInsured.txnRecNo
left join TxnAdditionalInsured on Txn.txnRecNo = TxnAdditionalInsured.txnRecNo
where Txn.visibleFlag=1
and Txn.workingCopy=1
A left join will produce all rows from the left side of the join at least once in the result set.
But if your join conditions are such that there are multiple rows from the right side that match a particular row on the left, that left row will appear multiple times in the result (as many times as it is matched with a right row).
So, if the results are unexpected, your join criteria aren't are strict as they need to be or you do not understand your data as well as you thought you did.
Unlike the other answers, I would not suggest just adding distinct - I'd suggest you investigate your data and determine whether your ON clause needs strengthening or if your data is in fact incorrect. Adding distinct to "make the results look right" is usually a poor decision - prefer to investigate and get the correct query written.
Try this:
select distinct Txn.txnRecNo --> added distinct here
from Txn
inner join Person on Txn.uwId = Person.personId
full outer join TxnInsured on Txn.txnRecNo = TxnInsured.txnRecNo
left join TxnAdditionalInsured on Txn.txnRecNo = TxnAdditionalInsured.txnRecNo
where Txn.visibleFlag=1
and Txn.workingCopy=1

SQL Cascading Join

I have the following join as part of a View:
from studies
inner join orders on orders.orderId = studies.orderId
left outer join referrers on referrers.referrerId = orders.referrerId
left outer join professionalDegrees referrerDegree on referrerDegree.professionalDegreeId = referrers.professionalDegreeId
referrers.professionalDegreeId column is NOT NULL. In queries that are limited to the referrers scope, the JOIN to professionalDegrees is INNER.
In the View above, if I INNER JOIN on professionalDegrees, there are no rows returned where orders.referrerId is NULL. When I LEFT JOIN on professionalDegrees the row is returned with NULL referrerId, as desired.
Does INNER vs LEFT matter to performance in this case? Is there a better way to write this JOIN?

SQL: Proper JOIN Protocol

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.

Combining OUTER JOIN and WHERE

I'm trying to fetch some data from a database.
I want to select an employee, and if available, all appointments and other data related to that employee.
This is the query:
SELECT
TA.id,
TEI.displayname,
TA.threatment_id,
TTS.appointment_date,
TEI.displayname
FROM
tblemployee AS TE
LEFT OUTER Join tblappointment AS TA ON TE.employeeid = TA.employee_id
Inner Join tblthreatment AS T ON TA.threatment_id = T.threatmentid
Inner Join tblappointments AS TTS ON TTS.id = TA.appointments_id AND
TTS.appointment_date = '2009-09-28'
INNER Join tblemployeeinfo AS TEI ON TEI.employeeinfoid = TE.employeeinfoid
Inner Join tblcustomercard AS TCC ON TCC.customercardid = TTS.customercard_id
WHERE
TE.employeeid = 4
The problem is, it just returns null for all fields selected when there are no appointments. What am I not getting here?
Edit:
For clearity, i removed some of the collumns. I removed one too many. TEI.displayname should at least be displayed.
Looking at the list of columns returned by your query, you will notice that they all come from the "right" side of the LEFT OUTER JOIN. You do not include any columns from the "left" side of the join. Therefore, the expected result is the one you are observing — NULL values supplied for all right-hand columns in the result set for those rows that have no right-hand rows returned.
To see data even for those rows, include some columns from TE (tblemployee) in the result set.
Looking at your query I'm guessing that the situation is a bit more complex and that some of those tables on the right-hand side of the join should be moved to the left-hand side and, furthermore, that some of the other tables might possibly require their own OUTER joins to participate correctly in the query.
Edited w/ response to questioner's comment:
You have an odd situation (maybe not odd at all, depending on your application) in which you have an employee table and a separate employee information (employeeinfo) table.
Because you are joining the employeeinfo to the appointments table with an INNER join you can effectively think of them as a single table in terms of how they contribute to the final result set. Because this combined table REQUIRES a record in the appointments table and because this combined table is joined into the main result set with a LEFT OUTER join, the effect is that the employeeinfo record is not found if there's no appointment to link it to.
If you move the employeeinfo table to the left side of the join, or replace the employee table w/ the employeeinfo table, you should get the results you want.
In your query, you LEFT OUTER JOIN to the tblappointment table, but then you INNER JOIN to the tblthreatment and tblappointments tables.
You should try and structure your query in the order that you expect data to be there. Then in most simple queries, once you perform an OUTER join, most tables after that will be an OUTER join. This is by NO MEANS a rule and complex queries can vary, but in the marjority of simple queries its a good practice.
Try something like this for your query.
SELECT
TA.id,
TEI.displayname,
TA.threatment_id,
TTS.appointment_date
FROM
tblemployee AS TE
INNER Join
tblemployeeinfo AS TEI
ON
TEI.employeeinfoid = TE.employeeinfoid
LEFT OUTER Join
tblappointment AS TA
ON
TE.employeeid = TA.employee_id
LEFT OUTER JOIN
tblthreatment AS T
ON
TA.threatment_id = T.threatmentid
LEFT OUTER JOIN
tblappointments AS TTS
ON
TTS.id = TA.appointments_id
AND
TTS.appointment_date = '2009-09-28'
LEFT OUTER JOIN
tblcustomercard AS TCC
ON
TCC.customercardid = TTS.customercard_id
WHERE
TE.employeeid = 4
The issue is that the way you're joining (most of everything is joining to your left outer-joined table) whenever you're joining off of that, if the value in the outer joined table is nothing, there is nothing for the other fields to join to. Try to re-adjust your query so everything is joining off of your employeeID. I normally use left joined tables after I've limited everything down as much as possible with inner joins.
So my query would be something like:
SELECT
TA.id,
TEI.displayname,
TA.threatment_id,
TTS.appointment_date
FROM
tblemployee AS TE
INNER Join tblemployeeinfo AS TEI ON TEI.employeeinfoid = TE.employeeinfoid
Inner Join tblthreatment AS T ON TA.threatment_id = T.threatmentid
Inner Join tblappointments AS TTS ON TTS.id = TA.appointments_id AND
TTS.appointment_date = '2009-09-28'
Inner Join tblcustomercard AS TCC ON TCC.customercardid = TTS.customercard_id
LEFT OUTER Join tblappointment AS TA ON TE.employeeid = TA.employee_id
WHERE
TE.employeeid = 4
where the last outer join just gives me one column worth of information, not using it all to join more things onto. For speed, you also want to try to limit your information down as fast as possible with your first few inner joins, and then you do the outer joins last to join possible null values on to the smallest dataset you can. I hope this helps, if it's confusing, I'm sorry... I haven't had my caffeine yet.
The query is performing as it should.
A left out join will select all records from one table, join them with the records in another, and produce nulls where no records in the second table are found that match the join condition.
If you're looking for a separate behavior, you may want to think about two separate queries.