SQL - How can you use WHERE instead of LEFT/RIGHT JOIN? - sql

since I am a bit rusty, I was practicing SQL on this link and was trying to replace the LEFT JOIN completly with WHERE. How can i do this so it does the same thing as the premade function in the website?
What I tried so far is:
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers, Orders
WHERE Customers.CustomerID = Orders.CustomerID OR Customers.CustomerID != Orders.CustomerID
Order by Customers.CustomerName;
Thanks in advance for your help.

You are trying to replace
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID
with
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers, Orders
WHERE ???
this is doomed to failure. Consider Customers has two rows and Orders has zero. The outer join will return two rows.
The cross join (FROM Customers, Orders) will return zero rows.
In standard SQL a WHERE clause can only reduce the rows from that - not increase them so there is nothing you can put for ??? that will give your desired results.
Before ANSI-92 joins were introduced some systems used to have proprietary operators for this, such as *= in SQL Server but this was removed from the product.

This may work for you.
SELECT
c.CustomerName,
o.OrderID
FROM Customers c
LEFT JOIN Orders o
on c.CustomerID = o.CustomerID
Order by c.CustomerName;

If you are trying to replace this:
SELECT c.CustomerName, o.OrderID
FROM Customers c LEFT JOIN
Orders o
ON c.CustomerID = o.CustomerID
ORDER BY c.CustomerName;
Then you can use UNION ALL:
SELECT c.CustomerName, o.OrderID
FROM Customers c JOIN
Orders o
ON c.CustomerID = o.CustomerID
UNION ALL
SELECT c.CustomerName, o.OrderID
FROM Customers c
WHERE NOT EXIST (SELECT 1 FROM Orders o WHERE c.CustomerID = o.CustomerID)
ORDER BY CustomerName
However, the LEFT JOIN is really a much better way to go.

Related

Select query with and/or in the from/join clause

Say I have SQL Select query like so:
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders
INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID;
is there a way to use AND/OR in the JOIN clause? something like this:
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders
INNER JOIN Customers ON (
Orders.CustomerID = Customers.CustomerID
AND
Orders.CustomerName = Customers.CustomerName
)
I am not even sure if that makes sense - but if this is possible, if someone knows the name of this type of query, let me know.
Yes, you can have multiple join condition.
Below queries are valid
Select a.a1, b.b1 from table1 a inner join table2 b on a.a1=b.a1 and a.b1=b.b1;
You can even have filters, functions as well.
Select a.a1, b.b1 from table1 a inner join table2 b on a.a1=b.a1 and a.b1=b.b1 and b.c1='someValue';
Select a.a1, b.b1 from table1 a inner join table2 b on a.a1=b.a1 and a.b1=b.b1 and <functions>
SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders
INNER JOIN Customers ON
Orders.CustomerID = Customers.CustomerID
AND Orders.CustomerName = Customers.CustomerName
Yes it is possible to join on multiple fields.
Yes, you can put any boolean expression in the on clause, even a reference to a subquery. So this is valid:
SELECT o.OrderID, c.CustomerName, o.OrderDate
FROM Orders o INNER JOIN
Customers c
ON o.CustomerID = c.CustomerID AND
o.CustomerName = c.CustomerName;
That said, you have a problem with your data model. You should not be storing the customer name twice -- in both the Orders table and the Customers table. It should be in the Customers table. And, you can look it up using CustomerId.
So, I would recommend fixing your data model so you don't need to use two keys for this JOIN.

LEFT JOIN vs Stacked Left Join

I wanted to ask whats the difference between those two queries:
SELECT
Customers.CustomerID, Customers.CustomerName, Orders.OrderID,
OrderDetails.Quantity, Products.ProductName
FROM
Customers
LEFT JOIN
(Orders
LEFT JOIN
(OrderDetails
LEFT JOIN
Products ON Products.ProductID = OrderDetails.ProductID
) ON OrderDetails.OrderID = Orders.OrderID
) ON Customers.CustomerID = Orders.CustomerID
GROUP BY
Customers.CustomerName;
Vs
SELECT
Customers.CustomerID, Customers.CustomerName, Orders.OrderID,
OrderDetails.Quantity, Products.ProductName
FROM
Customers
LEFT JOIN
Orders ON Orders.CustomerID = Customers.CustomerID
LEFT JOIN
OrderDetails ON OrderDetails.OrderID = Orders.OrderID
LEFT JOIN
Products ON Products.ProductID = OrderDetails.ProductID
GROUP BY
Customers.CustomerName;
Tested here
https://www.w3schools.com/sql/trysql.asp?filename=trysql_select_join
From what I can see one selects the first of multiple entries, one selects the last of multiple entries, but is that all?
From my point of view the not nested LEFT Join is way easier to read and to understand. Is there any downside of using it?
Your problem is the incorrect use of GROUP BY. The only unaggregated columns in the SELECT should be in the GROUP BY.
The rest of this answer addresses the point about joins.
Your second query is interpreted as:
FROM (((Customers c LEFT JOIN
Orders o
ON o.CustomerID = c.CustomerID
) LEFT JOIN
OrderDetails
ON od.OrderID = o.OrderID
) LEFT JOIN
Products p
ON p.ProductID = od.ProductID
The parentheses can affect the interpretation. But what effect? Essentially, you have:
(((c left join o) left join od) left join p)
versus
c left join (o left join (od left join p)))
Both keep all records in c, regardless of matches in the second. In this case, the two versions do the same thing. But for a particular reason -- the on conditions are strictly chained (that is, c to o, o to od, od to p). If p where joined to o instead of od, then subtle differences can occur.
What are the subtle differences? Two things can differ:
Whether columns from a particular table are NULL or have values.
Whether rows get duplicated, due to multiple matches between two tables.
In practice, I don't fine parentheses particularly useful. If I can about JOIN order, I use an explicit subquery or CTE>

How to Organize Multiple Joins SQL

In SQL, how should I be joining tables together when I do multiple joins in one query. Should I join on only one table - in this case the Customers table or is it okay to do what I have done (joining on different tables as new keys are needed)?
SELECT O.OrderID, O.OrderDate, C.City, C.Country, C.PostalCode, C.ContactName, O.CustomerID, O.ShipperID, D.ProductID, COUNT(D.ProductID) ProductCount, S.SupplierID
FROM Customers C
INNER JOIN Orders O
ON O.CustomerID = C.CustomerID
INNER JOIN OrderDetails D
ON O.OrderID = D.OrderID
INNER JOIN Products P
ON D.ProductID = P.ProductID
INNER JOIN Suppliers S
ON S.SupplierID = P.SupplierID
WHERE 1 = 1
GROUP BY O.OrderID
ORDER BY OrderDate DESC
I am using W3Schools SQL TryIt editor to test this, not sure what DB engine it is!
Thanks!
Of course you can join on multiple tables in a query. That is a big part of the power of SQL.
In your particular case, you don't need the join to the Suppliers table, because the column is already in Products.
Also, you need to be careful about your SELECT and GROUP BY clauses. In general, you should put all non-aggregated columns in the GROUP BY:
SELECT O.OrderID, O.OrderDate, C.City, C.Country, C.PostalCode, C.ContactName,
O.CustomerID, O.ShipperID, D.ProductID,
COUNT(D.ProductID) as ProductCount,
P.SupplierID
FROM Customers C INNER JOIN
Orders O
ON O.CustomerID = C.CustomerID INNER JOIN
OrderDetails D
ON O.OrderID = D.OrderID INNER JOIN
Products P
ON D.ProductID = P.ProductID
GROUP BY O.OrderID, O.OrderDate, C.City, C.Country, C.PostalCode, C.ContactName,
O.CustomerID, O.ShipperID, D.ProductID, P.SupplierId
ORDER BY OrderDate DESC;
The WHERE 1=1 is also unnecessary.
I wonder if this query really does what you want. However, you don't state what you actually want the query to do, so I'm merely speculating.
The way you have done it is find, don't forget that for each inner join, your record set may reduce by the number of non matching keys in each additional join.
you could also just use the JOIN syntax.

Left Join in Oracle SQL

I was going through an example of LEFT JOIN on w3schools.com.
http://www.w3schools.com/sql/sql_join_left.asp
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
LEFT JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;
The above query will return me all customers with No Orders as NULL Order ID+ All customers having Orders with their Order Ids
How should I modify this query so that it returns All Customers with No Orders + All Customers having Orders with Order date as '1996-09-18'
Thanks in advance.
If you want customers with no orders and those with a specific order date, then you want a WHERE clause:
SELECT c.CustomerName, o.OrderID
FROM Customers c LEFT JOIN
Orders o
ON c.CustomerID = o.CustomerID
WHERE (o.CustomerID is NULL) OR (o.OrderDate = DATE '1996-09-18)
ORDER BY c.CustomerName;
If you wanted all customers with their order on that date (if they have one), then you would move the condition to the ON clause:
SELECT c.CustomerName, o.OrderID
FROM Customers c LEFT JOIN
Orders o
ON c.CustomerID = o.CustomerID AND o.OrderDate = DATE '1996-09-18
ORDER BY c.CustomerName;
Note the difference: the first filters the customers. The second only affects what order gets shown (and NULL will often be shown).

SQL search query returns 'Syntax error in FROM clause'

Im a beginner and trying to learn SQL. On an exercise I was doing I entered the following query and got an error 'Syntax error in FROM clause'
select orders.customerid, customers.customername, count(orders.customerid)
from orders
join customers on customers.customerid = orders.customerid
group by orders.customerid
order by count(orders.customerid)
In the W3Schools SQL thingy the type of join used with the join keyword needs to be specified (inner, left, right).
Using join customers on customers.customerid = orders.customerid gives the error you got Syntax error in FROM clause.
Changing the join to an inner join fixes that error, but there's still another issue, the missing column in the group by statement: You tried to execute a query that does not include the specified expression 'customername' as part of an aggregate function.
After you fix that the query would look like:
select orders.customerid, customers.customername, count(orders.customerid)
from orders
inner join customers on customers.customerid = orders.customerid
group by orders.customerid, customers.customername
order by count(orders.customerid);
However, if you want to return all customers regardless if the have any orders you should change the query to use a left join:
select orders.customerid, customers.customername, count(orders.customerid)
from customers
left join orders on customers.customerid = orders.customerid
group by orders.customerid, customers.customername
order by count(orders.customerid);
On a side note, this might be a good time to pick up the use of aliases:
select o.customerid, c.customername, count(o.customerid) as count_of_orders
from customers as c
left join orders as o on c.customerid = o.customerid
group by o.customerid, c.customername
order by count(o.customerid);
See how much shorter the query became? :)