Left Join in Oracle SQL - 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).

Related

COUNT with LEFT JOIN

Two tables named Sales.Customers and Sales.Orders.
Sales.Customers has a foreign key relationship to a column
named CustomerID in Sales.Orders.
Requirement: A query that returns all the customers. The query must also return the number of orders that each customer placed.
Query 1:
SELECT cust.cutomername,
NumberofOrders= COUNT(ord.OrderID)
FROM Sales.Customers Cust
LEFT JOIN
Sales.Orders Ord
ON Cust.CustomerID=Ord.OrderID
GROUP BY
Cust.CutomerName;
But I'm thinking of below one also,
Query2:
SELECT cust.cutomername,
NumberofOrders= COUNT(Cust.cutomerID)
FROM Sales.Customers Cust
LEFT JOIN
Sales.Orders Ord
ON Cust.CustomerID=Ord.OrderID
GROUP BY
Cust.CutomerName;
From both which one do you recommend & why?
This query:
SELECT c.customername, COUNT(o.OrderID)
FROM Sales.Customers c LEFT JOIN
Sales.Orders o
ON c.CustomerID = o.OrderID
GROUP BY c.CustomerName;
Probably returns all customers with meaningless counts -- probably 0 except for OrderIDs that happen to match CustomerIDs.
You probably intend:
SELECT c.customername, COUNT(o.OrderID)
FROM Sales.Customers c LEFT JOIN
Sales.Orders o
ON c.CustomerID = o.CustomerId
GROUP BY c.CustomerName;
In this query, the COUNT() is counting the number of matching orders. It can take the value of 0 for customers with no orders.
For this query:
SELECT c.customername, COUNT(c.OrderID)
FROM Sales.Customers c LEFT JOIN
Sales.Orders o
ON c.CustomerID = o.CustomerID
GROUP BY c.CustomerName;
The COUNT() is returning the number of rows. Every customer has at least one row, so the value would never be 0. Normally, you want the previous query.
Maybe this is your solution:
select c.Customername,
NumberOfOrders = (select count(o.OrderID) from Sales.Orders o where o.CustomerID = c.CustomerID)
from Sales.Customers c
order by c.Customername

How do I make the GROUP BY clause in this query run?

Write a SELECT statement that returns three columns:
EmailAddress, OrderID, and the order total for each customer.
To do this, you can group the result set by the EmailAddress and OrderID columns.
In addition, you must calculate the order total from the columns in the OrderItems table.
SELECT c.EmailAddress, oi.OrderID, (oi.ItemPrice * oi.Quantity) -
oi.DiscountAmount
FROM Customers c JOIN Orders o ON c.CustomerID = o.CustomerID
JOIN OrderItems oi ON o.OrderID = oi.OrderID
GROUP BY c.EmailAddress, oi.OrderID
You are looking for GROUP BY and SUM():
SELECT c.EmailAddress, oi.OrderID,
SUM(oi.ItemPrice * oi.Quantity - oi.DiscountAmount)
FROM Customers c JOIN
Orders o
ON c.CustomerID = o.CustomerID JOIN
OrderItems oi
ON o.OrderID = oi.OrderID
GROUP BY c.EmailAddress, oi.OrderID;
Column must appear in the GROUP BY clause or be used in an aggregate function. Your column
(oi.ItemPrice * oi.Quantity) - oi.DiscountAmount
does not satisfy this requirement. I assume what you want to do is
sum((oi.ItemPrice * oi.Quantity) - oi.DiscountAmount)
?

SQL - Advanced "forensic" queries

I want to find out which one of the customers has purchased the largest total amount of items, with no date range
These are the columns I have:
customers.customerid
orders.orderid
orderdetails.productid
orderdetails.quantity
But I'm stuck here:
Start with customerid
Pull the orderid's from the customerid (using a join I assume)
Pull the quantity and individual productid's (another join? lol)
select * from orders returns 196 records.
select distinct customerid from orders returns 74 records, so that means 74 'distinct' customers placed orders
How to complete this?
First, find out how many items each customer ordered. To do that, you have to join the order detail and orders table:
select o.customerid, sum(od.quantity) as nbr_items
from orderdetail od
inner join orders o
on o.orderid = od.orderid
group by o.customerid
But if you need the customer name as well, which is fairly likely, you would have to join the customer table, too:
select o.customerid, sum(od.quantity) as nbr_items
from orderdetail od
inner join orders o
on o.orderid = od.orderid
inner join customer c
on c.customerid = o.customerid
group by o.customerid
But of course, you asked specifically for the customer with the MOST TOTAL AMOUNT of items, so sort descending by that total:
select o.customerid, sum(od.quantity) as nbr_items
from orderdetail od
inner join orders o
on o.orderid = od.orderid
inner join customer c
on c.customerid = o.customerid
group by o.customerid
order by 2 DESC
And use the TOP N function to get the first one only:
select top 1 o.customerid, sum(od.quantity) as nbr_items
from orderdetail od
inner join orders o
on o.orderid = od.orderid
inner join customer c
on c.customerid = o.customerid
group by o.customerid
order by 2 DESC

Compare a table with a count result from another table and add the names that have a zero count

I am counting how many times a company has ordered. Then I am only showing if a company has ordered less than 5 times. I am then checking it against the table with all company names to see what company has not ordered, which would not show up on the order table, then add their name on the displayed list.
What I have tried:
Select Orders.CustomerID, Count(Orders.CustomerID) AS OrderCount
From Orders Left Join Customers
On Orders.CustomerID = Customers.CustomerID
Group By Orders.CustomerID
Having Count(Orders.CustomerID) <5
This is totally wrong:
Select CustomerID
From Customers
Where EXISTS
(Select CustomerID, Count(CustomerID) AS 'OrderCount'
From Orders
Group BY CustomerID
Having Count(Orders.CustomerID) < 5)
I need to somehow compare the list of names before I ask it to see which ones have ordered less than 5 times.
Thanks
If you want to use LEFT JOIN, interchange the table names since you want to show values from Customers, otherwise use RIGHT JOIN instead.
SELECT Customers.CustomerID,
COUNT(Orders.CustomerID) AS OrderCount
FROM Customers
LEFT JOIN Orders
ON Orders.CustomerID = Customers.CustomerID
GROUP BY Customers.CustomerID
HAVING COUNT(Orders.CustomerID) < 5
using EXISTS()
SELECT CustomerID
FROM Customers c
WHERE EXISTS
(
SELECT 1
FROM Orders o
WHERE o.CustomerID = c.CustomerID
GROUP BY CustomerID
HAVING COUNT(CustomerID) < 5
)
Try this:
SELECT C.CustomerID, C.CustomerName, COUNT(O.CustomerID) AS OrderCount
FROM Customers C
LEFT JOIN Orders O ON O.CustomerID = C.CustomerID
GROUP BY C.CustomerID
HAVING OrderCount < 5
ORDER BY OrderCount, C.CustomerName

SQL - confused with aggregate

I currently have this query:
select
customers.emailaddress,
MAX(orders.orderdate) as "last order"
from orders
join customers
on orders.customerID = customers.customerID
group by customers.emailaddress
Which gives me the emails, and the last order date. With the 'Orders' table, there is a field named 'PaymentTotal', how can I get this based on the value returned by MAX(orders.orderdate)? (ie am trying to get the amount of the last order per email)
select c.EmailAddress, om.MaxOrderDate, o.PaymentTotal
from (
select CustomerID, MAX(orders.orderdate) as MaxOrderDate
from orders
group by CustomerID
) om
inner join orders o on om.CustomerID = o.CustomerID
and om.MaxOrderDate = o.orderdate
inner join customers c on o.customerID = c.customerID