Most efficient way to to find most expensive recent order - sql-server-2008

I am trying to find most recent and expensive purchase by customer. I have four tables customers,orders,order details and product code. All accounts are unique by emailaddress.
Error The multi-part identifier "cx.EmailAddress" could not be bound
SELECT c.EmailAddress,
o.BillingFirstName AS WC_FirstName,
o2.LatestOrder
FROM Customers c
JOIN orders o ON o.customerid = c.customerid
JOIN( SELECT
cx.EmailAddress,
MAX(o.OrderID) AS LatestOrder
FROM Customers AS cx
JOIN Orders o ON o.customerid = cx.customerid
WHERE o.OrderStatus <> 'CANCELLED' AND o.OrderDate > '09/01/2017 00:00'
GROUP BY EmailAddress) AS o2 on o2.EmailAddress = cx.EmailAddress
GROUP BY c.EmailAddress,o.BillingFirstName
UPDATE Tried it in another way too but still gets error : The multi-part identifier "c.EmailAddress" could not be bound.
SELECT
c.EmailAddress,
c.CustomerID,
o.OrderDate,
p.Google_Gender,
p.Google_Age_Group ,
p.productprice AS Product_Price
FROM
Customers c
JOIN
orders o ON o.CustomerID = c.CustomerID
JOIN
(SELECT
c.EmailAddress,
MAX(o.OrderID) AS LatestOrder
FROM
Orders o, Customers c
WHERE
o.OrderStatus <> 'CANCELLED' AND
o.CustomerID = c.CustomerID
GROUP BY
c.EmailAddress) AS o2 ON o2.EmailAddress = c.EmailAddress
JOIN
(SELECT
od.*,
c.EmailAddress,
row_number() over (partition BY c.EmailAddress
ORDER BY od.ProductPrice DESC, o.OrderDate DESC) AS seqnum
FROM
OrderDetails od
JOIN
Orders o ON od.OrderID = o.OrderID
JOIN
Customers c ON o.CustomerID = c.CustomerID
JOIN
(SELECT
c.EmailAddress,
MAX(o.OrderID) AS LatestOrder
FROM
Orders o , Customers c
WHERE
o.OrderStatus <> 'CANCELLED' AND
o.CustomerID = c.CustomerID
GROUP BY
c.EmailAddress) AS o2 ON o2.EmailAddress = c.EmailAddress
WHERE
o.OrderID = o2.LatestOrder) od ON od.CustomerID = c.CustomerID
AND seqnum = 1
JOIN
Products_Joined p ON od.ProductCode = p.ProductCode
FULL JOIN
(SELECT p.ProductCode, p.ProductName FROM Products_Joined AS p) AS p2 ON p2.ProductCode = p.Google_Age_Group
WHERE
AND o.PaymentAmount <> 0
AND o.OrderID = o2.LatestOrder
GROUP BY
c.EmailAddress, o.OrderDate, c.CustomerID, p.productprice,
p.Google_Age_Group, p.Google_Gender, p.Google_Pattern,
p.Google_Size, od.ProductName, p.ProductName, p2.productname,
p.productcode
ORDER BY
o.OrderDate DESC, MAX(od.ProductPrice) DESC;

You have that error because cx is an internal alias inside the o2 query. So you should probably change that JOIN condition for this one:
AS o2 on o2.EmailAddress = c.EmailAddress
This way you join your o2 email address with the one from Customers directly.
Just for the sake of performance, it would be better if you join customers by CustomerID, like you do in your first join, instead of by email.
Finally, you are doing the MAX of OrderID, which will most likely return the most recent order. Having that in mind, you should probably change your query to something like this (I'm guessing Amount is the name of the field):
SELECT c.EmailAddress,
o.BillingFirstName AS WC_FirstName,
MostExpensiveOrderId = o.OrderId,
MostExpensiveOrderAmount = o.Amount
FROM Customers c
INNER JOIN (
SELECT
CustomerID,
MAX(Amount)
FROM Orders
WHERE OrderStatus <> 'CANCELLED' AND OrderDate > '09/01/2017 00:00'
GROUP BY CustomerID
) AS omax ON omax.CustomerID = C.CustomerID
INNER JOIN Orders o ON o.CustomerID = c.CustomerID AND o.Amount = omax.Amount
ORDER BY c.EmailAddress, o.BillingFirstName
Note that you don't need the Customers table in the inner query. Also note that this way you may get more than one row per customer if the highest value is shared with more than one order.

Related

Remove duplication in SQL query

SQL Practice from W3Schools
SELECT C.country,
Round(Sum(P.price * OD.quantity), 2) AS Revenue
FROM [orders] AS O
INNER JOIN [orderdetails] AS OD
ON O.orderid = OD.orderid
INNER JOIN [products] AS P
ON OD.productid = P.productid
INNER JOIN [customers] AS C
ON O.customerid = C.customerid
WHERE C.country = (SELECT C.country
FROM [orders] AS O
INNER JOIN [orderdetails] AS OD
ON O.orderid = OD.orderid
INNER JOIN [products] AS P
ON OD.productid = P.productid
INNER JOIN [customers] AS C
ON O.customerid = C.customerid
GROUP BY C.customerid
ORDER BY Round(Sum(P.price * OD.quantity), 2) DESC
LIMIT 1)
My joins are duplicated from main to sub-query.
Is there anyway to reduce code replication in this query?

Retrieve customer who bought more than 13 different products who never purchased same product

I tried this. But I feel this gives people who ordered same product
SELECT DISTINCT Count(od.orderqty) OrderQty,
c.customerid,
od.productid
FROM sales.customer c
INNER JOIN sales.salesorderheader oh
ON c.customerid = oh.customerid
INNER JOIN sales.salesorderdetail od
ON oh.salesorderid = od.salesorderid
GROUP BY od.productid,
c.customerid
HAVING Count(od.productid) > 10
ORDER BY c.customerid
Not sure what flavor of SQL you're using but try this:
select t.CustomerID
from (
select c.CustomerID
, count(distinct od.ProductID) as DistinctCount
, count(od.ProductID) as Count
from Sales.Customer c
join Sales.SalesOrderHeader oh
on c.customerid = oh.customerid
join Sales.SalesOrderDetail od
on oh.SalesOrderID = od.SalesOrderID
group
by c.CustomerID
) as t
where t.DistinctCount = t.Count
and t.DistinctCount > 13
order
by t.CustomerID

MySQL - Using subqueries on join and from

I am trying to return the CustomerID, CompanyName, OrderID, and subtotals for each customer for all order the subtotal amounts that are higher than the customer’s average subtotal amount. These are the tables I am using and the query below. I am unsure if the values I return are correct and was hoping someone could help me understand if they are or not based on my query. Thanks in advance.
Orders
Columns
OrderID
CustomerID
EmployeeID
OrderDate
RequiredDate
OrderDetails
Columns
OrderID
ProductID
UnitPrice
Quantity
Products
Columns
ProductID
ProductName
QuantityPerUnit
UnitPrice
Customers
Columns
CustomerID
CompanyName
ContactName
Country
SELECT A.CustomerID, A.CompanyName, A.Subtotal, A.OrderID, AVGSubtotal
FROM (
SELECT
C.CustomerID,
C.CompanyName,
(D.UnitPrice * P.QuantityPerUnit) AS Subtotal,
D.OrderID
FROM Customers C
JOIN Orders O ON C.CustomerID = O.CustomerID
JOIN OrderDetails D ON D.OrderID = O.OrderID
JOIN Products P ON P.ProductID = D.ProductID
GROUP BY
D.OrderID, C.CustomerID
) A
JOIN (
SELECT
S.CustomerID, S.CompanyName, AVG(S.Subtotal) as AVGSubtotal
FROM (
SELECT
C.CustomerID,
C.CompanyName,
(D.UnitPrice * P.QuantityPerUnit) AS Subtotal
FROM Customers C
JOIN Orders O ON C.CustomerID = O.CustomerID
JOIN OrderDetails D ON D.OrderID = O.OrderID
JOIN Products P ON P.ProductID = D.ProductID
GROUP BY
D.OrderID, C.CustomerID
) S
GROUP BY
S.CustomerID
) B ON A.CustomerID = B.CustomerID
WHERE
A.CustomerID = B.CustomerID AND
A.Subtotal > B.AVGSubtotal
ORDER BY
A.CustomerID, A.CompanyName
;
select
c2.customerID,
c2.CompanyName,
c2.AVGSubtotal
o2.OrderID,
o2.UnitPrice * o2.Quantity as subtotal
from (
select
c.CustomerID,
c.CompanyName,
sum(o.UnitPrice * o.Quantity)/count(*) as AVGSubtotal
from
Customers c
inner join Orders o on (o.CustomerID = c.CustomerID)
inner join OrderDetails od on (od.OrderID = c.OrderID)
group by
o.CustomerID
) as c2
inner join Orders o2 on (o2.CustomerID = c2.CustomerID)
where o2.UnitPrice * o2.Quantity > c2.AVGSubtotal

How can I combine information from 4 different tables in a SQL query?

I have a to write an SQL query to list the names and total spend of customers who made more
than one order. The following lists all the relevant information but I'm struggling to see how to move forward with this.
SELECT l.quantity, o.orderID, i.itemID, o.custID, i.unitcost, c.familyname
FROM lineitems l, orders o, items i, customers c
WHERE l.itemID = i.itemID
AND c.custID = o.custID
AND o.orderID = l.orderID
ORDER BY o.custID
Select customerId, Sum(i.quantity*i.unitCost)
From lineitems I
join orders o on o.orderID = i.orderID
where Exists(Select * From orders
where customerId = o.customerId
having count(*) > 1)
group by customerId
or, with name instead of just customerId
Select c.familyname, Sum(i.quantity*i.unitCost)
From lineitems I
join orders o on o.orderID = i.orderID
join customers c on c.customerId = o.customerId
where Exists(Select * From orders
where customerId = o.customerId
having count(*) > 1)
group by c.familyname

Modify SQL query to get all users?

I currently have this query.
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM `order` AS o LEFT JOIN customer AS c ON o.customer_id = c.id
GROUP BY customer_id
What it does is it returns all customers that have made an order and counts the number of orders each customer has made.
What I need to do is modify this query so it also returns those customers who haven't made an order. Do you have any idea how this would be done?
I tried to reverse the query but this didn't do the trick..
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
GROUP BY o.customer_id
Try this.
SELECT o.customer_id, sum( case when o.id is not null then 1 else 0 end ) AS orders, c.*
FROM customer c
LEFT JOIN order o ON o.customer_id = c.id GROUP BY customer_id
What about:
SELECT DISTINCT (o.customer_id), count( o.id ) AS orders, c.*
FROM `order` AS o
LEFT OUTER JOIN customer AS c ON o.customer_id = c.id GROUP BY customer_id
SELECT o.customer_id, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
WHERE o.id IS NULL
GROUP BY o.customer_id
You can also skip the "GROUP BY" clause because when the orders side is NULL, there is always only one row for the customer:
SELECT o.customer_id, c.*
FROM customer AS c LEFT JOIN order AS o ON o.customer_id = c.id
WHERE o.id IS NULL