SQL - confused with aggregate - sql

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

Related

JOINS AND SUBQUERY

Question -
Display customer Id, name, and total number of orders, for orders handled by salesman Marshall, but only if customer name begins on General or ends on Electric. Exclude customers who placed a single order, but include customers without orders as well. Sort the result based on the total number of orders descending and then by name ascending.
Do not use LIKE operator and do not join 3 tables.
Questions output
Current Query
SELECT c.customer_id,
c.name,
Count(o.order_id) "# of Orders"
FROM customers c
left join orders o
ON c.customer_id = o.customer_id
WHERE Substr(c.name, 1, 7) = 'General'
OR Substr(c.name, -8) = 'Electric'
AND o.order_id IN (SELECT o.order_id
FROM orders o,
order_items oi
WHERE o.order_id = oi.order_id
AND o.salesman_id = (SELECT employee_id
FROM employees
WHERE
last_name = 'Marshall')
GROUP BY o.order_id
HAVING Count(customer_id) > 1)
GROUP BY c.customer_id,
c.name;
Database -
Not sure what I am doing wrong here.
That's a really contrived assignment... Here is one option:
select c.customer_id, c.customer_name, count(o.orderid) cnt
from customers c
left join orders o
on o.customer_id = c.customer_id
and (select last_name from employee e where e.employee_id = o.salesman_id) = 'Marshall'
where substr(c.name, 1, 7) = 'General' or substr(c.name, -8) = 'Electric'
group by c.customer_id, c.customer_name
having count(o.orderid) <> 1
The base idea is a left join. The where clause filters on the customer name - without like: you had that already.
To filter on the salesman name without an additional join, we use a correlated subquery in the on clause of the left join. There is no need to bring order_items, nor to select again from orders here.
Finally, the filtering on the order counts goes to the having clause.

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

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