Select all orders by one customer - sql

I have three tables, orders, orders_details and customers. I need to select orders by one customer for the orders table so I did this
orders columns:
id
customer_id
created
vat
discount
amount
paid
orders_details columns:
id
order_id
cost
qty
product
The SQL I used
SELECT
orders.*,
SUM(orders_details.qty*orders_details.cost) as amount,
SUM(orders_details.qty) AS qty
FROM
orders,
orders_details,
customers
WHERE
orders.customer_id = customers.id
AND orders_details.order_id = orders.id
AND orders.customer_id = 1
but I am getting a wrong qty of 30 instead of 20 and the amount is wrong

If you want to aggregate per order you need a GROUP BY clause. Also you should use proper JOIN syntax, and might consider using aliases to make the query more compact.
SELECT
o.*,
SUM(od.qty * od.cost) AS amount,
SUM(od.qty) AS qty
FROM orders o
INNER JOIN orders_details od ON od.order_id = o.id
INNER JOIN customers c ON o.customer_id = c.id -- not used, might be excluded
WHERE o.customer_id =1
GROUP BY o.id
Depending on what database system you are using you might need to include all columns referenced in o.* in the GROUP BY:
GROUP BY o.id, o.customer_id, o.created, o.vat, o.discount, o.amount, o.paid
Last note: as you don't seem to use any data from the customers table you probably could exclude that table altogether.

You're missing a GROUP BY clause which I'm guessing should be on orders.id.

Related

How to sort customer names by items purchased in SQL

Sorry new to this but,
I need to sort customer names by total quantity of items purchased by them, in desc order.
the purchased amount in the table is known as Inv_number
I would need the customer name and than the sum. This is what it should be
Thanks
I don't know what your tables are named or what fields they have on them, so I'll give a generic example:
SELECT c.CUST_NAME AS "cust_name",
SUM(oi.QTY_PURCHASED) AS "sum"
FROM CUSTOMERS c
INNER JOIN ORDERS o
ON o.ID_CUSTOMERS = c.ID_CUSTOMERS
INNER JOIN ORDER_ITEMS oi
ON oi.ID_ORDERS = o.ID_ORDERS
GROUP BY c.CUST_NAME
ORDER BY SUM(oi.QTY_PURCHASED) DESC,
c.CUST_NAME ASC
db<>fiddle here
Should work this way - you have to join the tables for customerinfo (customer in this script) and the items purchased (order_items). For simplicity I only made an example with two tables. if the customer_id is present in a kind of "order" table, you have to join order_items -> order -> customer
SELECT
x.customer_name,
y.customer_amount
FROM customer x
INNER JOIN (
SELECT
customer_id,
SUM(order_amount) AS customer_amount
FROM order_items
GROUP BY customer_id
) y ON x.id = y.customer_id
ORDER BY y.customer_amount DESC;

Query returning individuals most recent order, date of the order, number of products in the order and the total amount

Need help with a query to returns each individuals most recent order, date of the order, number of products in the order and the total amount. I am kind of stuck trying to get the number of products and total.
Here are the table diagrams
Not sure if I should be using multiple joins or subqueries:
SELECT FirstName, LastName, MAX(O.OrderDate), O.OrderDate
FROM Customer C
INNER JOIN Order O ON C.CustomerID = O.CustomerID
It is always good practice to start from assumed dim tables such as product.This Query should help. It is better to aggregate quantity and amount to get results at aggregate level
SELECT FirstName
,LastName
,max(o.orderdate) Orderdate
,Sum(Quantity) Quantity
,Sum(TotalAmount) TotalAmount
FROM Product p
INNER JOIN Orderitem oi
ON Oi.product_id = p.id
INNER JOIN
ORDER o
ON o.id = oi.order_id
INNER JOIN Customer c
ON c.id = o.Customer_id
GROUP BY FirstName
,LastName
not sure if you want aggregations but here you go:
SELECT customer.firstname, customer.lastname, COUNT(DISTINCT orderitem.productid), [order].totalamount
FROM [order] LEFT JOIN customer ON [order].customerid=customer.id LEFT JOIN orderitem ON order.id=orderitem.orderid
WHERE [order].date=MAX([order].date)
GROUP BY customer.firstname,customer.lastname, [order].totalamount
Still don't know why you are applying a where clause for the last order, it's up to you to keep or not the where condtion.

Having an issue with the last part of my Oracle SQL query

I'm having trouble with a problem (and yes it is homework).. The question is:
Write a SELECT statement that returns one row for each customer that has orders with these columns:
The email_address from the Customers table
A count of the number of orders
The total amount for each order (Hint: First, subtract the discount amount from the price. Then, multiply by the quantity.)
Return only those rows where the customer has more than 1 order.
Sort the result set in descending sequence by the sum of the line item amounts.
My query for this part works. It is:
SELECT email_address, COUNT(o.order_id) as number_of_orders, sum((item_price-discount_amount)*quantity) As Total
FROM Customers c JOIN Orders o
ON c.customer_id = o.customer_id
JOIN order_items oi on oi.order_id =o.order_id
GROUP BY email_address
HAVING COUNT (o.order_id) > 1
ORDER BY number_of_orders DESC;`
After that, I'm supposed to modify that query so that it only counts and totals line items that have an item_price value greater than 400. I can't seem to figure it out. Can someone please point me in the right direction?
BTW, it's the My Guitar Shop database.
You will have to add a filter for item_price greater than 400 assuming item_price is part of order_items table.
SELECT email_address, COUNT(o.order_id) as number_of_orders, sum((item_price-discount_amount)*quantity) As Total
FROM Customers c JOIN Orders o
ON c.customer_id = o.customer_id
JOIN order_items oi on oi.order_id =o.order_id
where oi.item_price > 400
GROUP BY email_address
HAVING COUNT (o.order_id) > 1
ORDER BY number_of_orders DESC;
SELECT email_address, COUNT(o.order_id) as number_of_orders, sum((item_price-discount_amount)*quantity) As Total
FROM Customers c JOIN Orders o
ON c.customer_id = o.customer_id
JOIN (
SELECT order_id,
CASE WHEN item_price < 400 THEN 0 ELSE item_price END,
--other columns you need
FROM order_items ) oi on oi.order_id =o.order_id
GROUP BY email_address
HAVING COUNT (o.order_id) > 1
ORDER BY number_of_orders DESC;
This is should work.
Also, you should always use table aliases when addressing a coulmn- even if there are no name clashed. It improves readability and prevent you from making nasty mistakes.

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 Server Aggregation using Max() and obtaining details from max() line.

I just took a final exam and one of the questions asked me to double join three tables, and report the max sale payout for each salesperson.
The tables have the following variables:
Salesperson(id, name)
Order(orderid, order_date, Cust_id, Saleperson_id, amount)
Customer(id, name)
After joining:
select salesperson.Name, Orders.Number, customer.Name, Orders.Amount
from Orders
join salesperson
on orders.Salesperson_id = salesperson.ID
join Customer
on customer.ID = orders.cust_id
What the instructed wanted was for me to find each salesperson's maximum sell (as found by order.amount). He also wanted the salesperson (salesperson.name), the order number of the max sale (orders.number), the customer the sale was with (customer.name), and the max sale amount. What is the most efficient way to do this problem? I have tried to use "group by salesperson.name", but I cannot because the orders.number and customer.name are never held in the aggregation.
I finished the problem this way
select
salesperson.name as Sales_Person,
orders.number as Order_Number,
customer.Name as Customer_Name,
orders.Amount as Sale_Amount
from salesperson
left join Orders
on salesperson.ID = orders.Salesperson_id
left join Customer
on orders.cust_id = customer.ID
where orders.Amount in (select max(orders.Amount)
from salesperson
join Orders
on salesperson.ID = orders.Salesperson_id
join Customer
on orders.cust_id = customer.ID
group by salesperson.name)
I know this is a bad way to do it. For instance, what if two different salesperson's max sale was equivalent? Max and min are not like count and sum because it is picking out one line from a aggregation, but the rules still apply. Also, you might notices that there is no real unique identifier in the joined table other than order.number which is not useful. Therefore, I would have to use some composite of salesperson.name and order.number.
Also, what do I do if I have to pick the top three sales for each salesperson? Should such an output be totally different code-wise than what would be required from just the first sale?
I keep bumping me head against this problem, and I would love to have a more professional approach to this problem.
SELECT
M.max_amount,
S.Name,
O.Number,
C.Name
FROM orders O
JOIN salesperson S
ON S.Salesperson_id = O.Salesperson_id
JOIN customer C
ON C.Customer_id = O.Customer_id
JOIN (
SELECT Salesperson_id, MAX(amount) max_amount
FROM Order
GROUP BY Salesperson_id
) M
ON M.Salesperson_id = O.Salesperson_id AND M.max_amount = O.amount
For the top 3:
SELECT
M.Amount,
S.Name,
O.Number,
C.Name
FROM orders O
JOIN salesperson S
ON S.Salesperson_id = O.Salesperson_id
JOIN customer C
ON C.Customer_id = O.Customer_id
CROSS APPLY (
SELECT TOP 3 Amount
FROM Order
WHERE Salesperson_id = O.Salesperson_id
ORDER BY Amount DESC
) M