Find customer who bought least on W3schools SQL - 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
);

Related

SQL query with subquery and without subquery comparison

I'd like someone who can explain me the logic difference between these two queries. Maybe you can explain performance difference also. (DB is Microsoft Northwind).
-- Join
select distinct c.CustomerID, c.CompanyName, c.ContactName from orders as o inner join customers as c
on o.CustomerID = c.CustomerID
-- SubQuery
select customerid, companyname, contactname, country from customers
where customerid in (select distinct customerid from orders)
Thanks in advance.
The first generates an intermediate result set with all orders for all customers. It then reduces them using select distinct.
The second just selects the customers without having to reduce them later. It should be much more efficient. However, the select distinct is not needed in the subquery (it is done automatically with in).
I would write the logic as:
select c.customerid, c.companyname, c.contactname, c.country
from customers c
where exists (select 1
from orders o
where o.customerid = c.customerid
);
This can readily make use of an index on orders(customerid).

Sql query to display records that appear more than once in a table

I have two tables, Customer with columns CustomerID, FirstName, Address and Purchases with columns PurchaseID, Qty, CustomersID.
I want to create a query that will display FirstName(s) that have bought more than two products, product quantity is represented by Qty.
I can't seem to figure this out - I've just started with T-SQL
You could sum the purchases and use a having clause to filter those you're interested in. You can then use the in operator to query only the customer names that fit these IDs:
SELECT FirstName
FROM Customer
WHERE CustomerID IN (SELECT CustomerID
FROM Purchases
GROUP BY CustomerID
HAVING SUM(Qty) > 2)
Please try this, it should work for you, according to your question.
Select MIN(C.FirstName) FirstName from Customer C INNER JOIN Purchases P ON C.CustomerID=P.CustomersID Group by P.CustomersID Having SUM(P.Qty) >2
Please try this:
select c.FirstName,p.Qty
from Customer as c
join Purchase as p
on c.CustomerID = p.CustomerID
where CustomerID in (select CustomerID from Purchases group by CustomerID having count(CustomerID)>2);
SELECT
c.FirstName
FROM
Customer c
INNER JOIN Purchases p
ON c.CustomerId = p.CustomerId
GROUP BY
c.FirstName
HAVING
SUM(p.Qty) > 2
While the IN suggestions would work they are kind of overkill and more than likely less performant than a straight up join with aggregation. The trick is the HAVING Clause by using it you can limit your result to the names you want. Here is a link to learn more about IN vs. Exists vs JOIN (NOT IN vs NOT EXISTS)
There are dozens of ways of doing this and to introduce you to Window Functions and common table expressions which are way over kill for this simplified example but are invaluable in your toolset as your queries continue to get more complex:
;WITH cte AS (
SELECT DISTINCT
c.FirstName
,SUM(p.Qty) OVER (PARTITION BY c.CustomerId) as SumOfQty
FROM
Customer c
INNER JOIN Purchases p
ON c.CustomerId = p.CustomerId
)
SELECT *
FROM
cte
WHERE
SumOfQty > 2

Double check simple SQL query - customer and orders tables

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

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

Not understanding why I am getting this error

This is the code I did
SELECT TOP 5 ContactName FROM Customers
INNER JOIN [Order Details]ON OrderId =
CustomerID
INNER JOIN Orders ON ProductID = OrderID
WHERE UnitPrice >= 25000
ORDER BY ContactName ASC
But this is the error I am getting
Msg 209, Level 16, State 1, Line 5
Ambiguous column name 'orderID'
Can someone explain to me why I am getting this error.
This is what I am trying to do is show the most recent five orders that were purchased from a customer who has spent more than $25,000
So i am assuming to use order,product,and customer.
The column OrderID exists in both tables.
There is probably an OrderID column in both your Order Details and your Orders table, and SQL Server doesn't know which one to take.
Solution: specify which one you want to use by putting the table name in front of it:
Orders.OrderID instead of just OrderID
So your query would look like this then:
SELECT TOP 5 ContactName FROM Customers
INNER JOIN [Order Details]ON Orders.OrderId =
CustomerID
INNER JOIN Orders ON ProductID = Orders.OrderID
WHERE UnitPrice >= 25000
ORDER BY ContactName ASC
Almost certainly you have the field orderID in both the Details and the Orders table.
Clarify it with either Orders.orderID or Details.orderID.
There are 2 OrderID columns across the tables.
You can remove the ambiguity with aliases (like this) or use Orders.OrderID
SELECT TOP 5 C.ContactName
FROM
Customers C
INNER JOIN
[Order Details] OD ON C.OrderId = OD.CustomerID
INNER JOIN
Orders O ON OD.ProductID = O.OrderID
WHERE O.UnitPrice >= 25000 -- or OD?
ORDER BY C.ContactName ASC
Note: did you mean to joion Customers and [Order Details] like using Customers.OrderId?
When you JOIN multiple tables in the same query, you need to differentiate any columns which have the same name in multiple tables. Otherwise, how would the query engine know which one you're talking about?
You can do this either by prefixing the column name with <table name>. or <table alias>..
For example:
SELECT TOP 5
C.ContactName
FROM
Customers C -- Customers is aliased as "C"
INNER JOIN [Order Details] OD ON
OD.OrderId = C.CustomerID
INNER JOIN Orders O ON
OD.ProductID = O.OrderID
WHERE
OD.UnitPrice >= 25000
ORDER BY
C.ContactName ASC
Another important question... are you sure that you're joining on the correct columns there? It looks really wrong.
Finally, if this is for a homework assignment, please make sure that you tag it as such with the "homework" tag.
In your references to OrderId, you need to figure out which table you are pulling the orderId column from. (In some cases, you can just pick either table). Let's call that table .
In your query, replace orderId with .orderId.