Condition on main table in inner join vs in where clause - sql

Is there any reason on an INNER JOIN to have a condition on the main table vs in the WHERE clause?
Example in INNER JOIN:
SELECT
(various columns here from each table)
FROM dbo.MainTable AS m
INNER JOIN dbo.JohnDataRecord AS jdr
ON m.ibID = jdr.ibID
AND m.MainID = #MainId -- question here
AND jdr.SentDate IS NULL
LEFT JOIN dbo.PTable AS p1
ON jdr.RecordID = p1.RecordID
LEFT JOIN dbo.DataRecipient AS dr
ON jdr.RecipientID = dr.RecipientID
(more left joins here)
WHERE
dr.lastRecordID IS NOT NULL;
Query with condition in WHERE clause:
SELECT
(various columns here from each table)
FROM dbo.MainTable AS m
INNER JOIN dbo.JohnDataRecord AS jdr
ON m.ibID = jdr.ibID
AND jdr.SentDate IS NULL
LEFT JOIN dbo.PTable AS p1
ON jdr.RecordID = p1.RecordID
LEFT JOIN dbo.DataRecipient AS dr
ON jdr.RecipientID = dr.RecipientID
(more left joins here)
WHERE
m.MainID = #MainId -- question here
AND dr.lastRecordID IS NOT NULL;
Difference in other similar questions that are more general whereas this is specific to SQL Server.

In the scope of the question,
Is there any reason on an INNER JOIN to have a condition on the main
table vs in the WHERE clause?
This is a STYLE choice for the INNER JOIN.
From a pure style reflection point of view:
While there is no hard and fast rule for STYLE, it is generally observed that this is a less often used style choice. For example that might generally lead to more challenging maintenance such as if someone where to remove the INNER JOIN and all the subsequent ON clause conditions, it would effect the primary table result set, OR make the query more difficult to debug/understand when it is a very complex set of joins.
It might also be noted that this line might be placed on many INNER JOINS further adding to the confusion.

Related

What is the best way to write inner join query in SQL?

First Way:
SELECT ST.PersonID, ST.CustomerID, ST.SaleTypeID, ST.PaymentGatewayID,
ST.CustomerMembershipID, ST.CustomerPaymentGatewayID, P.Currency
FROM ServiceTransaction ST
INNER JOIN dbo.Person P ON ST.PersonID = P.PersonID;
Second Way:
SELECT ST.PersonID, ST.CustomerID, ST.SaleTypeID, ST.PaymentGatewayID,
ST.CustomerMembershipID, ST.CustomerPaymentGatewayID, P.Currency
FROM ServiceTransaction ST
INNER JOIN dbo.Person P ON P.PersonID = ST.PersonID;
I want to optimize this query in SQL. Currently I am using second way and I need expert opinion, which one is best approach.
However, any one can add some new way to optimize this query as well.
As comments suggest, they are identical in many aspects. For a personal note tho if you keep the same format it gets easier to follow so I use the following schema to keep tabs on tables where I always use lower numbered table on left side
SELECT Column_list
FROM TABLE1
INNER JOIN TABLE2
INNER JOIN TABLE3
ON Table1.ColName = Table2.ColName
ON Table1.ColName = Table3.ColName | ON Table2.ColName = Table3.ColName
This way when you are working with multiple tables and joins it is easier to follow which table is joined where and which table was mentioned first in the query.

SQL: JOIN vs LEFT OUTER JOIN?

I have multiple SQL queries that look similar where one uses JOIN and another LEFT OUTER JOIN. I played around with SQL and found that it the same results are returned. The codebase uses JOIN and LEFT OUTER JOIN interchangeably. While LEFT JOIN seems to be interchangeable with LEFT OUTER JOIN, I cannot I cannot seem to find any information about only JOIN. Is this good practice?
Ex Query1 using JOIN
SQL
SELECT
id,
name
FROM
u_users customers
JOIN
t_orders orders
ON orders.status=='PAYMENT PENDING'
Ex. Query2 using LEFT OUTER JOIN
SQL
SELECT
id,
name
FROM
u_users customers
LEFT OUTER JOIN
t_orders orders
ON orders.status=='PAYMENT PENDING'
As previously noted above:
JOIN is synonym of INNER JOIN. It's definitively different from all
types of OUTER JOIN
So the question is "When should I use an outer join?"
Here's a good article, with several great diagrams:
https://www.sqlshack.com/sql-outer-join-overview-and-examples/
The short answer your your question is:
Prefer JOIN (aka "INNER JOIN") to link two related tables. In practice, you'll use INNER JOIN most of the time.
INNER JOIN is the intersection of the two tables. It's represented by the "green" section in the middle of the Venn diagram above.
Use an "Outer Join" when you want the left, right or both outer regions.
In your example, the result set happens to be the same: the two expressions happen to be equivalent.
ALSO: be sure to familiarize yourself with "Show Plan" (or equivalent) for your RDBMS: https://www.sqlshack.com/execution-plans-in-sql-server/
'Hope that helps...
First the theory:
A join is a subset of the left join (all other things equal). Under some circumstances they are identical
The difference is that the left join will include all the tuples in the left hand side relation (even if they don't match the join predicate), while the join will only include the tuples of the left hand side that match the predicate.
For instance assume we have to relations R and S.
Say we have to do R JOIN S (and R LEFT JOIN S) on some predicate p
J = R JOIN S on (p)
Now, identify the tuples of R that are not in J.
Finally, add those tuples to J (padding any attribute in J not in R with null)
This result is the left join:
R LEFT JOIN S (p)
So when all the tuples of the left hand side of the relation are in the JOIN, this result will be identical to the Left Join.
back to you problem:
Your JOIN is very likely to include all the tuples from Users. So the query is the same if you use JOIN or LEFT JOIN.
The two are exactly equivalent, because the WHERE clause turns the LEFT JOIN into an INNER JOIN.
When filtering on all but the first table in a LEFT JOIN, the condition should usually be in the ON clause. Presumably, you also have a valid join condition, connecting the two tables:
SELEC id, name
FROM u_users u LEFT JOIN
t_orders o
ON o.user_id = u.user_id AND o.status = 'PAYMENT PENDING';
This version differs from the INNER JOIN version, because this version returns all users even those with no pending payments.
Both are the same, there is no difference here.
You need to use the ON clause when using Join. It can match any data between two tables when you don't use the ON clause.
This can cause performance issue as well as map unwanted data.
If you want to see the differences you can use "execution plans".
for example, I used the Microsoft AdventureWorks database for the example.
LEFT OUTER JOIN :
LEFT JOIN :
If you use the ON clause as you wrote, there is a possibility of looping.
Example "execution plans" is below.
You can access the correct mapping and data using the ON clause complement.
select
id,
name
from
u_users customers
left outer join
t_orders orders on customers.id = orders.userid
where orders.status=='payment pending'

Odd Outer Joining Structure for a View

I am importing a view from an old database as part of a software upgrade and I saw this FROM clause as I was working.
FROM
t_store_master AS STM
RIGHT OUTER JOIN
dbo.t_shipping AS SHP
INNER JOIN
t_hu_master AS HUM
INNER JOIN
t_stored_item AS STO ON HUM.hu_id = STO.hu_id
ON SHP.shipment_id = HUM.reserved_for
AND SHP.location_id = HUM.location_id
INNER JOIN
dbo.t_carrier AS CAR ON SHP.carrier_code = CAR.carrier_code
LEFT OUTER JOIN
dbo.t_order_detail AS ORD
INNER JOIN
dbo.t_order AS ORM ON ORD.order_number = ORM.order_number
INNER JOIN
dbo.t_pick_detail PDL ON ORD.order_number = PDL.order_number
ON STO.type = PDL.pick_id
ON STM.store_id = HUM.control_number_2
It is my understanding that OUTER JOIN requires an ON clause in order to be interpreted properly by the compiler. However, there must be some edge case scenarios I am unaware of because the code above returns good data without throwing any errors.
After some goggling and reading up on MSDN standards for OUTER JOINs, I am still at a loss for what the LEFT OUTER JOIN and RIGHT OUTER JOIN are doing in this query.
I do know that the multiple ON clauses beneath the INNER JOINs are necessary. There seems to be some kind of hidden or implied mapping being done between the ON clauses and the OUTER JOINs. Past that I cannot tell what the purpose of writing a query this way would be.
Could someone shed some insight on how this works and why it would be written this way?
This is allowed. It makes slightly more sense with parentheses:
FROM t_store_master STM RIGHT OUTER JOIN
(dbo.t_shipping SHP INNER JOIN
(t_hu_master HUM INNER JOIN
t_stored_item STO
ON HUM.hu_id = STO.hu_id
)
ON SHP.shipment_id = HUM.reserved_for AND
SHP.location_id = HUM.location_id
) INNER JOIN
(dbo.t_carrier CAR
ON SHP.carrier_code = CAR.carrier_code LEFT OUTER JOIN
((dbo.t_order_detail ORD INNER JOIN
dbo.t_order ORM
ON ORD.order_number = ORM.order_number
) INNER JOIN
dbo.t_pick_detail PDL
ON ORD.order_number = PDL.order_number
)
ON STO.type = PDL.pick_id
)
ON STM.store_id = HUM.control_number_2
That said, I would recommend never writing a query like this and rewriting the query ASAP if it is in production code. At the very least, add the parentheses!
Parentheses are almost never needed in the FROM clause to express JOINs (there is one case where I do happen to use them). Non-interleaved ON clauses are never needed -- or at least, I have never had occasion to use them or think they were the best way to write a query. But, both are allowed.

Is there a option to clean this SQL query up

I was wondering if it was possible to make this query smaller
SELECT Templates.TempName
,TimeSpans.TimeSpan
,TemplateSlotTypes.[Type]
,TemplateSlots.Potition
,TemplateSlots.duration
FROM TimeSpans
INNER JOIN Templates ON Templates.TimeSpanId = TimeSpans.Id
INNER JOIN TemplateSlots ON Templates.Id = TemplateSlots.TemplateId
INNER JOIN TemplateSlotTypes ON TemplateSlots.[Type] = TemplateSlotTypes.Id
It seems that you need all the parts of this query, so there's nothing that can just be dropped from the query.
You could, however, use table aliases to reduce the amount of text:
SELECT t.TempName, tsp.TimeSpan, tst.[Type], ts.Potition, ts.duuration
FROM TimeSpans tsp
INNER JOIN Templates t ON t.TimeSpanId = tsp.Id
INNER JOIN TemplateSlots ts ON t.Id = ts.TemplateId
INNER JOIN TemplateSlotTypes tst ON ts.[Type] = tst.Id
Table aliases will make the joins less verbose, but assuming the field names are unique to the tables involved you don't need to prefix them with the table name.
SELECT TempName
,TimeSpan
,[Type]
,Potition
,duration
FROM TimeSpans ts
INNER JOIN Templates t ON t.TimeSpanId = ts.Id
INNER JOIN TemplateSlots s ON t.Id = s.TemplateId
INNER JOIN TemplateSlotTypes st ON s.[Type] = st.Id
However, I would recommend the use of a good IDE for SQL query development where it performs the joins for you and removes a lot of the typing.
Manually reducing the amount of text in a query is a false economy in the long run. It can actually make the SQL harder to read, and therefore more time consuming to modify or debug in the future.

Refactor SQL (workaround RIGHT OUTER JOIN)

Since SQLite does not support RIGHT OUTER JOINS I pose the following challenge (read: invitation to do my work for me):
Refactor this query so it no longer utilises SQLite-unsupported constructs like RIGHT/FULL OUTER JOINs.
SELECT strings.*, translations.text
FROM translations INNER JOIN
language ON translations.language_id = language.id RIGHT OUTER JOIN
strings ON translations.string_id = strings.id
WHERE (language.handle = 'english')
I sense it can be achieved with subqueries or by pivoting the tables and performing a LEFT OUTER JOIN but my attempts have failed; my SQL's not what it used to be.
Here's a query builder outline showing the applicable schema: http://dl.getdropbox.com/u/264612/sql-refactor.PNG
First to crack it gets an e-hug from dekz
The following is untested.
select strings.*, translations.text
from strings left outer join translations
on translations.string_id = strings.id
and translations.language_id = (select id
from language
where language.handle = 'english')
I think this will give you all strings with the matching translation text where a suitable translation exists in English. Is that what you are trying to get?
Intriguing that SQLite allows LEFT OUTER JOINs but not RIGHT OUTER JOINs. Well, since it does allow LEFT OUTER JOINs, you're right, you can just rearrange the join order:
SELECT strings.*, translations.text
FROM strings LEFT OUTER JOIN (
translations INNER JOIN language ON translations.language_id = language.id
) tr ON tr.string_id = strings.id
WHERE (language.handle = 'english')
[EDIT: Applied Blorgbeard's suggestion of naming the joined table to get the query to parse -- hope it works now!]