Select top and order from two tables - sql

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.

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
);

using subquery in order to join columns from two tables

i started learning SQL and there is something i dont understand
i want to take the columns product_id and product_name from Production.products
and join it with the quantity column from the Production.stocks table
but instead of using join i want to use a subquery.
this is the code i wrote so far:
and i don't understand why it isn't working :(
SELECT P.product_id, P.product_name,(
SELECT S.quantity
FROM Production.stocks AS S
WHERE S.product_id = P.product_id)
FROM Production.products as P;
First, let's clear up the fact that it is not recommended to use a subquery at all. Do it only for your own research reasons; if you have performance or code clarity in mind, go with the simple join.
When you make a subquery on the SELECT clause by enclosing it in parenthesis, you are forcing the result to be one single value. If not, you get the error you receive.
Usually, subqueries are used in the FROM clause, where they should be given a name and then represent a table. Like this:
SELECT P.product_id, P.product_name,S.quantity
FROM Production.products as P
inner join
(
SELECT quantity
FROM Production.stocks
) as S on S.product_id = P.product_id
You can see from the simplicity of the subquery of how little use it is.
You can use SUM keyword for prevent error and give you total quatity.
SELECT P.product_id, P.product_name,(
SELECT SUM(S.quantity)
FROM Production.stocks AS S
WHERE S.product_id = P.product_id)
FROM Production.products as P;
I don't see a need at all for a subquery.
If the products are unique entities then surely a join onto the stocks table and doing a sum on the quantity would be more beneficial in terms of query performance
SELECT
Production.Products.Product_id,
Production.Products.product_name,
SUM(Production.Stocks.quantity) AS Quantity
FROM
Production.Products
LEFT JOIN
Production.Stocks
ON
Production.Stocks.product_id = Production.Products.product_id
GROUP BY
Production.Products.product_id,
Production.Products.product_name
If you need it to quote stock quantities by store then you need to add an addition join onto stores and add the store to the select and group by clause like so
SELECT
Production.Products.Product_id,
Production.Products.product_name,
Sales.Stores.store_name,
SUM(Production.Stocks.quantity) AS Quantity
FROM
Production.Products
LEFT JOIN
Production.Stocks
ON
Production.Stocks.product_id = Production.Products.product_id
LEFT JOIN
Sales.Stores
ON
Production.Stocks.store_id = Sales.Stores.store_id
GROUP BY
Production.Products.product_id,
Production.Products.product_name,
Sales.Stores.store_name
Hope that helps
did you mean select all data from products table and show quantity column for each product?
SELECT P.product_id, P.product_name, isnull(s.quantity, 0) as Quantity
FROM Production.products as P
left join Production.stocks AS S
on p.product_id = S.product_id
if you have one to many relation with Products and Stocks you should use subquery like this
SELECT P.product_id, P.product_name, isnull(s.quantity, 0) as Quantity
FROM Production.products as P
left join (
select product_id, sum(quantity) as Quantity
from Production.stocks
group by product_id)
as S on p.product_id = S.product_id
it will be produced aggregated sum value for quantity field

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

How do I use SQL to select rows that have > 50 related rows in another table?

I've been trying to find out how to write this query in sql.
What I need is to find the productnames (in the products table) that have 50 or more orders (which are in the order table).
only one orderid is matched up to a productname at a time so when I try to count the orderid's it counts all of them.
I can get distinct productnames but once i add in the orderid's then it goes back to having multiple productnames.
I also need to count the number of customers (in the order table) that have ordered those products.
I need some serious help ASAP! if anyone could help me figure out how to figure this out that would be awesome!
Table: Products
`productname` in the form of a text like 'GrannySmith'
Table: Orders
`orderid` in the form of '10222'..etc
`custid` in the form of something like 'SMITH'
Assuming the orders table has a field that relates back to the products table named ProductId. The SQL would translate to:
SELECT p.ProductName, Count(*)
FROM Orders o
JOIN Products p
on o.ProductId = p.ProductId
GROUP BY p.ProductName HAVING COUNT(*) >= 50
The key is in the having component of the Group By clause. I hope this helps.
You might be missing an "Order Details" table - typically, an order has several order details, and each of the order details then maps to a product - something like the sample in Northwind:
In that case, your SQL query would be something like this: join the [Order Details] table to both the [Orders] and [Products] tables, group by the product ID and name, and count the OrderID's:
select
p.ProductID, p.ProductName, count(o.OrderID)
from
[order details] od
inner join
orders o on od.OrderID = o.OrderID
inner join
products p ON od.productID = p.ProductID
group by
p.ProductID, p.ProductName
having
count(o.OrderID) > 50

SQL Query to find the maximum of a set of averages

This is a query based on the Northwind Database in MS SQL Server 2005.
First I have to get the average of the UnitPrice from OrderDetails table, and group it by ProductID for that particular column alone and alias it as AveragePrice.
Then I need to find the maximum(AveragePrice) which is nothing but the max of previous column, how can I do it??? This is a kind of very tricky for me its taking me ages to think on it.
select
O.CustomerID,
E.EmployeeID,
E.FirstName+space(1)+E.LastName FullName,
OD.OrderID,
OD.ProductID,
(select avg(DO.UnitPrice) from OrderDetails
DO where OD.ProductID = DO.ProductID
group by DO.ProductID) AveragePrice ,
from OrderDetails OD
join Orders O
on OD.OrderID = O.OrderID
join Customers C
on C.CustomerID = O.CustomerID
join Employees E
on E.EmployeeID = O.EmployeeID
This is not a Homework question, am learning SQL, but am really stuck at this point, please help me.
It's 2 steps: "the ungrouped maximum of the grouped averages"
You can expand this as needed which shows how to apply an aggregate on top of an aggregate
SELECT
MAX(AveragePrice) AS MaxAveragePrice
FROM
(
select
avg(UnitPrice) AS AveragePrice, ProductID
from
OrderDetails
group by
ProductID
) foo
Or with CTE
;WITH AvgStuff AS
(
select
avg(UnitPrice) AS AveragePrice
from
OrderDetails
group by
ProductID
)
SELECT
MAX(AveragePrice) AS MaxAveragePrice
FROM
AvgStuff