Double check simple SQL query - customer and orders tables - sql

I just wanted to double check this SQL query that I wrote. I want to return the top five customer first names based on the dollar amount ordered? I'm using a table called "customer" and table called "orders". However, I can't remember if I need to use a "max" somewhere.... Any help is appreciated!
SELECT TOP 5
customer.customerFirstName
FROM customer
LEFT JOIN orders
ON customer.customerID = orders.customerID
ORDER BY orders.orderCost DESC

You need a group by, I think:
SELECT TOP 5 c.customerFirstName
FROM customer c LEFT JOIN
orders o
ON c.customerID = o.customerID
GROUP BY c.customerFirstName
ORDER BY SUM(o.orderCost) DESC;

i think this should help answer your question, http://www.w3schools.com/sql/sql_join_left.asp
SELECT TOP 5 orders.orderid,
orders.customerid,
customers.customername
From customers
LEFT JOIN orders
ON customers.customerid=orders.customerid
ORDER by orders.orderid DESC

Related

Find customer who bought least on W3schools SQL

I'm new to SQL Server and I'm trying to do some exercises. I want to find customers who bought least on W3schools database. My solution for this case is:
Join Customers with OrderDetails via CustomerID
Select CustomerNames that have least OrderID appeared after using JOIN.
Here is my query:
SELECT COUNT(OrderID), CustomerID
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(CustomerID) ASC
HAVING COUNT(OrderID) = '1'
When I ran this query, message says "Syntax error near "Having". What happened with my query?
Please help me to figure out.
My solution for this case is:
Join Customers with OrderDetails via CustomerID
Select CustomerNames that have least OrderID appeared after using JOIN.
As #thorsten-kettner lamented:
You say in your explanation that you join and then show the customer
name. Your query does neither of the two things...
Furthermore, your question has severe grammatical errors making it hard to decipher.
I want to find customers who bought least on W3schools database.
Nonetheless,
The Try-SQL Editor at w3schools.com
To get the list of customers who have at least 1 order:
SELECT C.CustomerName FROM [Customers] AS C
JOIN [Orders] AS O
ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
ORDER BY C.CustomerName
To get the list of customers who have exactly 1 order:
SELECT C.CustomerName FROM [Customers] AS C
JOIN [Orders] AS O
ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
HAVING COUNT(O.OrderID) = 1
ORDER BY C.CustomerName
To get the customer who made the least number of orders:
Including the ones who made no order. Use JOIN instead of LEFT JOIN if you only want to consider the ones who made at least one order.
You can remove LIMIT 1 to get the whole list sorted by the number of orders placed.
SELECT C.CustomerName, COUNT(O.OrderID) FROM [Customers] AS C
LEFT JOIN [Orders] AS O
ON C.CustomerID = O.CustomerID
GROUP BY C.CustomerID
ORDER BY COUNT(O.OrderID), C.CustomerName
LIMIT 1;
Addendum
As commented by #sticky-bit ,
The ORDER BY clause has to come after the HAVING clause.
You want a TOP 1 WITH TIES query, something like this:
SELECT TOP 1 WITH TIES CustomerID
FROM Orders
GROUP BY CustomerID
ORDER BY COUNT(OrderID);
In case you are using MySQL, try the following version:
SELECT CustomerID
FROM Orders
GROUP BY CustomerID
HAVING COUNT(OrderID) = (
SELECT COUNT(OrderID)
FROM ORDERS
GROUP BY CustomerID
ORDER BY COUNT(OrderID)
LIMIT 1
);

Beginner: LEFT JOIN not doing what it should?

I'm having trouble with a really simple left join statement that's driving me nuts
I wanted to count the numbers of orders from each customer, that's fine, but I want to display the name, and I'm joining with the customers table and trying to select the name and it says that CustomerName is not part of an aggregate function, it's really weird.
SELECT Customers.CustomerName as 'Name',
COUNT(*) AS 'Order Count'
FROM Orders
LEFT JOIN Customers
ON Orders.CustomerID = Customers.CustomerID
GROUP BY Customers.CustomerID
Thanks for any tips.
You need to count the rows from the orders table, and the left join should be in the other direction:
SELECT c.customerid,
c.CustomerName as "Name",
COUNT(o.customerid) AS "Order Count"
FROM Customers c
LEFT JOIN Orders o ON o.CustomerID = cs.CustomerID
GROUP BY c.CustomerID, c.customername;
count() will ignore NULL values that come into the result due to the outer join so it will count the number of orders for each customers. Customers without orders will be show with a zero count.
Include CustomerName in Group BY instead of CustomerID
SELECT Customers.CustomerName as 'Name', COUNT(*) AS 'Order Count'
FROM Orders LEFT JOIN Customers ON Orders.CustomerID = Customers.CustomerID
GROUP BY Customers.CustomerName
If you are using SQL Server then try using OVER() without Group BY
SELECT Customers.CustomerName as 'Name', COUNT(*) OVER (PARTITION BY Customers.CustomerName ORDER BY Customers.CustomerName)AS 'Order Count'
FROM Orders LEFT JOIN Customers ON Orders.CustomerID = Customers.CustomerID
Modify as below. column used in group by clause should be in column queried in select clause
SELECT Customers.CustomerName as 'Name',
COUNT(*) AS 'Order Count'
FROM Orders
LEFT JOIN Customers
ON Orders.CustomerID = Customers.CustomerID
GROUP BY Customers.CustomerName
I have just reordered your query,please try this it will definitely work for you.
SELECT Customers.CustomerName as 'Name',
COUNT(*) AS 'Order Count'
FROM Customers
LEFT JOIN Orders
ON Customers.CustomerID=Orders.CustomerID
GROUP BY Customers.CustomerID
A simple approach to get all the columns in the customers table is to use a correlated subquery:
select c.*, -- or whatever columns you want
(select count(*)
from orders o
where o.CustomerID = c.CustomerID
) as order_count
from customers c;
Because this avoids the outer GROUP BY, this also has the advantage of having better performance in most databases, particularly with an index on orders(CustomerId). Plus, it returns 0 if the customer has no orders. And, it allows you to choose any or all of the columns from Customers.
The correct way to get the counts you want is to count a column from Orders:
SELECT c.CustomerName, c.CustomerID,
COUNT(o.CustomerId) AS Order_Count
FROM Customers c LEFT JOIN
Orders o
ON o.CustomerID = c.CustomerID
GROUP BY c.CustomerID, c.CustomerName;
Notes:
The Customers table goes first in the LEFT JOIN because presumably you want all rows in Customers.
Table aliases make the query easier to write and to read.
Do not use single quotes for column aliases, even if your database supports it. The best method is to choose aliases that do not need to be supported.
Include the CustomerId in the logic, just in case two customers have the same name.
Count a column from Orders so you get a count of 0 for customers with no orders.

Group by and inner join: how to select joined without a "max" trick

Here is a simple query:
SELECT orders.id, customers.name, COUNT(order_product.id)
FROM orders
INNER JOIN order_product ON orders.id = order_product.order_id
INNER JOIN customers ON orders.customer_id = customers.id
GROUP BY orders.id;
In other words, I want:
The ID of an order.
The number of products (count) in each order.
The customer name of the order.
The problem is about selecting customers.name. I cannot select it directly because it's not in aggregate function nor group by. But there is only one, so I d'ont know why I have to aggregate it. I can do a trick like this to select its name:
SELECT MAX(customers.name)
But I think it's dirty, because I don't want the "max name of a customer for an order" but "the name of the customer for an order". What is the elegant way to do such a thing?
Hope it's clear and not a duplicate.
EDIT: an order have only one customer identified by orders.customer_id. That's why I asking why I have to do such a trick.
Add customers.name to the GROUP BY clause:
SELECT orders.id, customers.name, COUNT(order_product.id)
FROM orders
INNER JOIN order_product ON orders.id = order_product.order_id
INNER JOIN customers ON orders.customer_id = customers.id
GROUP BY orders.id, customers.name
Usually you can simply group by all selected columns that are not arguments to set functions!
Alternatively, you could use window functions
SELECT DISTINCT orders.id, customers.name, COUNT(order_product.id) OVER ( PARTITION BY orders.id)
FROM orders
INNER JOIN products ON orders.id = order_product.order_id
INNER JOIN customers ON orders.customer_id = customers.id;

Select all orders by one customer

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.

Select top and order from two tables

I am doing an e-commerce marketplace. There are many sellers selling in this marketplace. For each seller, I would like to display a Best Sellers list.
Database is in SQL Server. There are 2 main tables in this case:
Table 1: Stores each order's ordered products. Fields include SellerID, OrderID, ProductID, and Quantity.
Table 2: The products master table. Fields include ProductID, ...
How can I do a query to get the top 10 products with the most orders? My SQL below doesn't seem to work...
SELECT TOP (10) SUM(d.Quantity) AS total, d.ProductID, p.Title
From OrderDetails d, Products p
WHERE d.SellerID = 'xxx' AND
d.ProductID = p.ProductID
GROUP by d.ProductID
ORDER BY total DESC
Any help is much appreciated. Thank you!
select *, d.s
from products p
inner join
(
select top 10 productid, sum(quantity) as s
From OrderDetails
group by productid
order by sum(quantity) desc
)
d on d.productid = p.productid
See this SQLFiddle example
This is just a guess. If you want the "most orders" then I would rather count the orders instead of summing the quantity.
SELECT TOP 10
COUNT(d.OrderID) AS total, d.ProductID, p.Title
FROM OrderDetails d
INNER JOIN Products p ON d.ProductID = p.ProductID
WHERE d.SellerID = 'xxx'
GROUP by d.ProductID, p.Title
ORDER BY COUNT(d.OrderID) DESC
What else I fixed:
GROUP BY was missing a column. You have to name every column you have in your SELECT clause but is not in an aggregate function.
In the ORDER BY clause you have to name it exactly like you did in SELECT clause. Aliases don't work well in SQL Server.
Used the INNER JOIN syntax, which is less error prone to forgetting to specify the join in the WHERE clause.
This is not because of what type of database you using but aggregate function. There are lots of q & a regarding of this problem in stackoverflow. Please search for it.