MYSQL Queries - combination - mysql

I need to find the first and last name of the customer who has purchased the most expensive product.
Schema
Orders
orderID
ordertypeID
customerID
quantity
purchasedate
Customers
customerID
state
postcode
streetNumber
streetAddress
customerLn
customerFn
Order_Contents
orderID
productID
quantity
Products
productID
productCategory
productName
productDescription
unitPrice
inStock
How can i write this query?

You can use sub queries as follows.
select
Customers.customerFN,
Customers.customerLN
from
Customers
inner join Orders on Orders.customerID = Customers.customerID
inner join Order_Contents on Order_Contents.orderID = Orders.orderID
where
Order_Contents.productID in
(select Products.productID from Products where Products.unitPrice = (select max(Products.unitPrice) from Products))

Something like this seems like it should work as a jumping off point (completely naive approach here)
SELECT CustomerFn, CustomerLn FROM Customers c
LEFT JOIN Orders o on o.customerID = c.customerID
LEFT JOIN Order_Contents oc on oc.orderID = o.orderID
LEFT JOIN Products p on p.productID = oc.productID
WHERE oc.productID IN (
SELECT productID FROM Products WHERE unitPrice = MAX(unitPrice)
);

select c.customerFn, c.customerLn
from customers c join orders o where o.customerID = c.customerID
join order_contents l where l.orderId = o.orderId
join products p where p.productId = l.productId
order by p.unitPrice desc
limit 1

Related

2 layer SQL join

I'm pretty new to sql.
I have the following db schema:
Customers
CustomerID number
Name string
Address string
Country string
OrderDetails
OrderDetailID number
OrderID number
ProductID number
Quantity number
Orders
OrderID number
CustomerID number
OrderDate string
OrderValue string
Products
ProductID number
ProductName string
Price number
I need to get the CustomerID and Quantity for all those that have ordered a particular product name = "oil"
So far I can get the quantity by
select OrderDetails.Quantity
FROM Products
INNER JOIN OrderDetails ON OrderDetails.ProductID = Products.ProductID
where Products.ProductName = 'oil'
I can get the CustomerID by following Products.ProductID -> OrderDetails.ProductID -> OrderDetails.OrderID -> Orders.OrderID -> Orders.CustomerID but I am unsure how to express this in sql.
EDIT:
I'm looking for a single table like:
CustomerID | Quantity
-----------------------
1 10
4 40
5 1
Testing:
I'm using the SQL to regular expression calculator here using the gist here
select customers.name,sum(OrderDetails.Quantity) as tot_qty
FROM Products
INNER JOIN OrderDetails ON OrderDetails.ProductID = Products.ProductID
inner join orders on orderdetails.orderid=orders.orderid
inner join customers on orders.customerid=customers.customerid
where Products.ProductName = 'oil'
group by customers.name
What you need is to aggregate the quantities per CustomerId.
Since you only require the customerId there's no need to join to the Customer table.
Note also the use of short meaningful aliases makes the query less verbose:
select o.CustomerId, Sum(od.Quantity) Quantity
from Products p
join OrderDetails od on od.ProductID = p.ProductID
join orders o on o.orderid = od.orderid
where p.ProductName = 'oil'
group by o.CustomerId;
Forget about the distinct, use group by instead.
Use sum() aggregated function to consolidate all orders
select sum(OrderDetails.Quantity) as total, OrderDetails.CustomerID
FROM Products
INNER JOIN OrderDetails ON OrderDetails.ProductID = Products.ProductID
INNER JOIN Orders O ON O.OrderId = ON.OrderId
where Products.ProductName = 'oil'
group by Order.CustomerID

MYSQL: How to Select Customers That Bought One Product But Not Another

I am working on a database and I would like to get the list of all the customers that bought a product with a name containing citroen but none with a name containing guzzi.
The structure of the database is the following:
I have tried the following:
SELECT customerName, productName
FROM customers c
INNER JOIN orders o
USING (customerNumber)
INNER JOIN orderdetails od
USING (orderNumber)
INNER JOIN products p
USING (productCode)
WHERE productName LIKE '%citroen%'
AND productName NOT IN (
SELECT productCode
FROM products
WHERE productName LIKE '%guzzi%'
);
but it selects also the one who bought guzzi.
Any clue?
Conditional aggregation to count how many products of each type were purchased...
SELECT
o.customerNumber
FROM
orders o
INNER JOIN
orderdetails od
USING (orderNumber)
INNER JOIN
products p
USING (productCode)
WHERE
p.productName LIKE '%citroen%'
OR p.productName LIKE '%guzzi%'
GROUP BY
o.customerNumber
HAVING
MAX(CASE WHEN p.productName LIKE '%citroen%' THEN 1 ELSE 0 END) = 1
AND MAX(CASE WHEN p.productName LIKE '%guzzi%' THEN 1 ELSE 0 END) = 0
Longer, but can be faster if each customer has (on average) a very large number of relevant purchases...
SELECT
*
FROM
customer
WHERE
EXISTS (
SELECT
o.customerNumber
FROM
orders o
INNER JOIN
orderdetails od
USING (orderNumber)
INNER JOIN
products p
USING (productCode)
WHERE
o.customerNumber = customer.CustomerNumber
AND p.productName LIKE '%citroen%'
)
AND NOT EXISTS (
SELECT
o.customerNumber
FROM
orders o
INNER JOIN
orderdetails od
USING (orderNumber)
INNER JOIN
products p
USING (productCode)
WHERE
o.customerNumber = customer.CustomerNumber
AND p.productName LIKE '%guzzi%'
)
In your last condition, you're comparing productName with productCode, so I suppose the NOT IN will always return TRUE.
SELECT customerName, productName
FROM customers c
INNER JOIN orders o
USING (customerNumber)
INNER JOIN orderdetails od
USING (orderNumber)
INNER JOIN products p
USING (productCode)
WHERE productName LIKE '%citroen%'
AND NOT EXISTS (
SELECT 'x'
FROM orders o2
INNER JOIN orderdetails od2
USING (orderNumber)
INNER JOIN products p2
USING (productCode)
WHERE o2.customerNumber = c.customerNumber
AND p2.productName LIKE '%guzzi%'
)
AND productName NOT LIKE '%guzzi%'
;```

Write an SQL Query to calculate total purchase amount of each customer

I'm trying to calculate the total purchase amount of each customer from the database available online on W3 Schools
The tables I'm using are:
Customers
Orders
Products
OrderDetails
My current query gives me the product wise purchase amount for the customer. What I need is the total purchase amount.
SELECT c.CustomerID,o.OrderID,(ord.Quantity*p.Price) as
Total_Amount
from Customers c inner join Orders o
inner join Products p
inner join OrderDetails ord
on c.CustomerID = o.CustomerID
and o.OrderID = ord.OrderID
and ord.ProductID = p.ProductID;
My Output:
I need the sum for the values with the same order id and customer id.
I tried out group-by and sum but it gives me the overall sum of all the products.
You simply want a GROUP BY:
SELECT c.CustomerID, SUM(ord.Quantity*p.Price) as
Total_Amount
FROM Customers c inner join Orders o
on c.CustomerID = o.CustomerID join
OrderDetails ord
on o.OrderID = ord.OrderID join
Products p
on ord.ProductID = p.ProductID
GROUP BY CustomerID;
Note that this orders the JOINs so the ON clauses are interleaved. This is how JOINs are normally written.
If you need the sum for the values with the same order id and customer id, then you need to group the rows based on both customer id and order id.
SELECT c.CustomerID,o.OrderID,SUM(ord.Quantity*p.Price) as Total_Amount
from Customers c inner join Orders o
inner join Products p
inner join OrderDetails ord
on c.CustomerID = o.CustomerID
and o.OrderID = ord.OrderID
and ord.ProductID = p.ProductID
Group By c.CustomerID,o.OrderID

SQL Get all orders which contain exclusively one kind of item

In this Database I want to count the number of orders that contain only products of a certain category.
I know how to count all orders that also contain items of a certain category, i.e. category 1:
SELECT Count(DISTINCT orderdetails.orderid) AS "AllCat1"
FROM orderdetails
INNER JOIN orders
ON orderdetails.orderid = orders.orderid
AND orderdetails.productid IN (SELECT DISTINCT productid
FROM products
WHERE categoryid = 1)
WHERE orderdate BETWEEN "1996-12-01" AND "1996-12-31";
I am having trouble finding an elegant way to get all orders that contain only category 1 items. I tried selecting all OrderIDs and grouping them by OrderID AND CategoryID:
SELECT *
FROM orderdetails
INNER JOIN orders
ON orderdetails.orderid = orders.orderid
AND orderdate BETWEEN "1996-12-01" AND "1996-12-31"
INNER JOIN products
ON orderdetails.productid = products.productid
GROUP BY orderdetails.orderid,
categoryid;
But I have no idea how to count all OrderIDs that contain category 1 items exclusively. Is my approach right? Or is there a better way to do it (Which I am sure there is)
You can use group by and having . . . but you need two levels. To get the orders that are all in one (or a set of categories) by doing:
SELECT o.orderId
FROM orders o JOIN
orderdetails od
ON od.orderid = o.orderid JOIN
products p
ON p.productid = od.productid
WHERE o.orderdate BETWEEN '1996-12-01' AND '1996-12-31'
GROUP BY o.orderId
HAVING SUM(CASE WHEN p.categoryid IN (1) THEN 1 ELSE 0 END) = COUNT(*);
The count needs a subquery:
SELECT COUNT(*)
FROM (SELECT o.orderId
FROM orders o JOIN
orderdetails od
ON od.orderid = o.orderid JOIN
products p
ON p.productid = od.productid
WHERE o.orderdate BETWEEN '1996-12-01' AND '1996-12-31'
GROUP BY o.orderId
HAVING SUM(CASE WHEN p.categoryid IN (1) THEN 1 ELSE 0 END) = COUNT(*)
) o;
You can do filtering using HAVING clause. We basically Count the order details rows where category is 1 for an order. It should be equal to the total count of rows for that order. This would ensure that all the categories in an order is 1 only.
SELECT od.orderid
FROM orderdetails AS od
INNER JOIN orders AS o
ON od.orderid = o.orderid
AND o.orderdate BETWEEN "1996-12-01" AND "1996-12-31"
INNER JOIN products AS p
ON od.productid = p.productid
GROUP BY od.orderid
HAVING COUNT(CASE WHEN p.categoryid = 1 THEN 1 END) = COUNT(*)
It is advisable to use Aliasing in case of multi-table queries for Code clarity and readability

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