COUNT with LEFT JOIN - sql

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

Related

SQL query number of orders

I have two tables, customers and orders, and I want to get the number of orders made by each customer.
I tried
SELECT orders.order_id, customers.customer_id,
FROM customers
INNER JOIN orders ON orders.customer_id = customers.customer_id
but I can't count number of orders
You are describing aggregation:
SELECT c.customer_id, count(*) no_orders
FROM customers c
INNER JOIN orders o ON o.customer_id = c.customer_id
GROUP BY c.customer_id
If you also want customers that have no order, use a LEFT JOIN instead, or a correlated subquery:
SELECT
c.customer_id,
(SELECT COUNT(*) FROM orders o WHERE o.customer_id = c.customer_id) no_orders
FROM customers c

sql use aggregate function that counts a unique value with group by using inner joins

I searched and found similar questions online but not my particular one, they all use where or having clause.If theres one similar to mine please link it. It's a 2 part question and I have the first one done. Thank you in advance.
Okay so heres the question, part 1
"Find by customer, the total cost and the total discounted cost for each product on the order ?".
It also asks to use inner joins to find the customer and order it a specific way. Below is the answer.
SELECT
C.companyname, O.orderid, O.orderdate, P.productname,
OD.orderid, OD.unitprice, OD.qty, OD.discount,
(OD.unitprice * OD.qty - (OD.qty * OD.discount)) AS TotalCost,
(OD.qty * OD.discount) AS TotalDiscountedCost
FROM
Sales.Customers AS C
INNER JOIN
Sales.Orders AS O ON C.custid = O.custid
INNER JOIN
Sales.OrderDetails OD ON O.orderid = OD.orderid
INNER JOIN
Production.Products as P ON OD.productid = P.productid
ORDER BY
C.companyname, O.orderdate;
Now the second question is to
follow up and resume the first one by "customer and the order date year, the total cost and the total discounted cost on the order ?". It also asks for this, "Project following columns in the select clause as.
GroupByColumns.companyname
GroupByColumns.OrderdateYear
AggregationColumns.CountNumberOfIndividualOrders
AggregationColumns.CountNumberOfProductsOrders
AggregationColumns.TotalCost
AggregationColumns.TotalDiscountedCost
Finally to order by company name and orderdateYear( which are groups). Where im stuck is how to count the specific orders of qty that equal 1 as an aggregate function in the SELECT clause. I know it has to use the aggregate function COUNT because of the GROUP BY, just don't know how to. This is what I have.
SELECT
C.companyname, YEAR(O.orderdate) AS orderyear,OD.qty,
-- Where in the count function or if theres another way do I count all the
--single orders
--COUNT(OD.qty) AS indiviualorders,
(OD.unitprice * OD.qty - (OD.qty * OD.discount)) AS TotalCost,
(OD.qty * OD.discount) AS TotalDiscountedCost
FROM
Sales.Customers AS C
INNER JOIN
Sales.Orders AS O ON C.custid = O.custid
INNER JOIN
Sales.OrderDetails OD ON O.orderid = OD.orderid
INNER JOIN
Production.Products as P ON OD.productid = P.productid
GROUP BY
C.companyname, YEAR(O.orderdate)
ORDER BY
C.companyname, O.orderdate;
You case use a case statement inside a sum
SUM(CASE WHEN <xyz> THEN 1 ELSE 0 END)
But for the count of unique orders, use SELECT(DISTINCT ) on a key that is unique in the order table
SELECT COUNT(DISTINCT O.OrderID) As DistinctOrders FROM Table

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)
?

Why this LEFT OUTER JOIN is not including all the Primary Keys from the Left

The customers table has total 1000 customers of which 1500 placed orders in FY 2016. But we want to display all the customers with their total number of orders in FY 2016 whether a customer placed an order in that FY or not. But the following query in SQL Server 2012 is displaying only 1490.
What we may be missing here?
SELECT c.CustomerID, count(*) AS TotalOrders
FROM Customers c
LEFT JOIN Orders o ON c.CustomerID = o.CustomerID
WHERE o.FiscalYear = '2016'
GROUP BY c.CustomerID
UPDATE:
The following query returns only 1 more record (1491) - still missing 9 more records.
SELECT c.CustomerID, count(*) AS TotalOrders
FROM Customers c
LEFT JOIN Orders o ON c.CustomerID = o.CustomerID
AND o.FiscalYear = '2016'
GROUP BY c.CustomerID
You where clause is turning the left outer join into an Inner join.
Change it to AND:
SELECT c.CustomerID, count(o.CustomerID) AS TotalOrders
FROM Customers c
LEFT JOIN Orders o
ON c.CustomerID = o.CustomerID
AND o.FiscalYear = '2016' -- Here
GROUP BY c.CustomerID
The correct SQL is:
SELECT c.CustomerID, count(o.CustomerID) AS TotalOrders,
sum(count(o.CustomerID)) over () as TotalTotalOrders
FROM Customers c LEFT JOIN
Orders o
ON c.CustomerID = o.CustomerID AND o.FiscalYear = '2016'
GROUP BY c.CustomerID;
TotalTotalOrders should be all the orders (or at least the ones with valid customer ids).
This will list all customers, whether or not they have any orders regardless of the year in which the order was placed. The sum will then count all orders that were placed in 2016, ignore the rest, and return an intenger (i.e. it will never be null).
SELECT
c.CustomerID
,sum(case when o.FiscalYear = '2016' then 1 else 0 end) AS TotalOrders
FROM Customers c
LEFT JOIN Orders o
ON c.CustomerID = o.CustomerID
GROUP BY c.CustomerID

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).