Didn't find an answer for this in previous questions..
I have a scope in a model A
A.activated
which does pretty complex queries and joins, but it works properly.
I want to join A to B table as a LEFT OUTER JOIN but only the rows in A that are in the scope
B.joins(:c).joins("LEFT OUTER JOIN a ON a.some_column = c.some_other_column") <--- how to add the scope?
So the answer is the fabulous #merge, don't leave home with it!
B.joins(:c).joins("LEFT OUTER JOIN a ON a.some_column = c.some_other_column").merge(A.activated)
Ta da!
Related
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'
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.
I am trying to use a RIGHT and LEFT Join together. I have it working when only left joining one table. But I am trying to now include another table in my left join. It gives me an error saying I am missing an operator. Where am I missing a parenthesis?
FROM qSplit RIGHT JOIN (t_i360_agent AS i LEFT JOIN cmsAgent_Split AS c
ON ((i.LocalDay = c.LocalDay) AND (i.ACDID = c.LOGID))
LEFT JOIN qry_AllNewtables as qry ON (qry.custConvDate = c.LocalDay)
AND (qry.CustAgentLoginName = i.Loginname) ) ON qSplit.SPLIT = c.SPLIT
Don't use LEFT JOIN and RIGHT JOIN together. I imagine that somewhere there could be a query where it makes sense. In practice, I don't think I have ever used them both in the same query, possibly because I write queries using LEFT JOIN.
If you want everything in the agent table, then make it first! And use left join;
FROM t_i360_agent i LEFT JOIN
cmsAgent_Split c
ON i.LocalDay = c.LocalDay AND i.ACDID = c.LOGID LEFT JOIN
qry_AllNewtables qry
ON qry.custConvDate = c.LocalDay AND
qry.CustAgentLoginName = i.Loginname LEFT JOIN
qSplit
ON qSplit.SPLIT = c.SPLIT
It is much easier to follow the intention of the query this way. You are starting with the data that you think is so important that you want to keep all of it, even when JOINs have no matching rows.
Beside the suggestion by Gordon the problem was you miss a join condition for the RIGHT JOIN once I reformat the query was easy to see what was missing.
FROM qSplit
RIGHT JOIN t_i360_agent AS i
-- Need join condition
LEFT JOIN cmsAgent_Split AS c
ON (i.LocalDay = c.LocalDay)
AND (i.ACDID = c.LOGID))
LEFT JOIN qry_AllNewtables as qry
ON (qry.custConvDate = c.LocalDay)
AND (qry.CustAgentLoginName = i.Loginname)
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.
I have 4 tables in SQL Server 2012. This is my diagram:
I have this query:
SELECT
pc.Product_ID, d.Dept_ID, c.Category_ID, sc.SubCategory_ID
FROM
dbo.ProductConfiguration pc
INNER JOIN
dbo.SubCategory sc ON sc.SubCategory_ID = pc.SubCategory_ID
INNER JOIN
dbo.Category c ON c.Category_ID = sc.Category_ID
INNER JOIN
dbo.Department d ON d.Dept_ID = c.Dept_ID
WHERE
pc.Product_ID = 459218
What is the best way, (INNER, LEFT, RIGHT) to get columns values? I need be careful with performance
Thanks a lot
This has nothing to do with performance.
I suppose every product belongs to a subcategory which belongs to a category which belongs to a department. So you inner join all the tables; this is the normal thing to do.
If one of the entities were not mandatory, but optional, say there are categories that don't belong to a department 1, but you still wanted to show the row, then you'd outer join the table. You'd use a left outer join on departments. We never use right outer joins, because these are supposed to be harder to read, and they do essentially the same as left joins.
1) i.e. category.dept_id coud be null
your query best variant is LEFT JOIN, from its do not loses your information
I would recommend to you, use execution plans when you need to update the performance. using execution plan you can understand the behaviors. it will grate help for future.
Thank You!