SQL query sum()/join/order by/ - what's wrong? - sql

I learning SQL, using Northwind example database and I'm completely stuck on very simple problem:
I want to list all products name in one column and total quantities sold for each product in second column.
First, I did this:
select p.ProductId
,sum(od.Quantity) as TotalQuantity
from Products p
join [Order Details] od
on p.ProductId=od.Productid
group by p.ProductId
and that's ok - I have product id's and total quantities, but when I try something like this:
select p.productid
,p.ProductName
, sum(od.quantity) as TotalQuantity
from products p
join [Order details] od
on p.productid=od.productid
group by p.productid
I get error:
Msg 8120, Level 16, State 1, Line 1
Column 'products.ProductName' is invalid in the select list because
it is not contained in either an aggregate function or the GROUP BY clause.`

When you use aggregate functions (like sum) you have to group by every other field in select
You have to modify your query as follows
select p.productid, p.ProductName, sum(od.quantity) as TotalQuantity from
products p join [Order details] od on p.productid=od.productid
group by p.productid, p.ProductName

Given that you will never going to get different ProductNames for a single ProductId, you can also try:
select p.productid
, min(p.ProductName) as ProductName
, sum(od.quantity) as TotalQuantity
from products p
join [Order details] od
on p.productid=od.productid
group by p.productid

Related

Find the most popular month for customers to order a certain product

I am trying to find out which month has the most orders for a certain product (Product HHYDP). This is my code so far, but each time I try to use GROUP BY and SORT BY functions related to my problem, I get an error. There are three years in the database (2006,2007,2008) and they are formatted as (YYYY-MM-DD). I am trying to find which month has the highest total order volume across the three years, quantity is irrelevant.
SELECT p.productname, o.orderdate
FROM [Sales].[Orders] as o
JOIN [Sales].[OrderDetails] as od
ON o.orderid = od.orderid
JOIN [Production].[Products] as p
ON od.productid = p.productid
WHERE p.productname like '%hhydp%'
I am using microsoft SQL management server.
You can try to use year and month with COUNT aggregate function function and add them in group by
SELECT p.productname,
year(o.orderdate) yr,
month(o.orderdate) mn,
COUNT(*) cnt
FROM [Sales].[Orders] as o
JOIN [Sales].[OrderDetails] as od
ON o.orderid = od.orderid
JOIN [Production].[Products] as p
ON od.productid = p.productid
WHERE p.productname like '%hhydp%'
GROUP BY p.productname, year(o.orderdate) ,month(o.orderdate)

Stuck doing a common table expression to calculate total orders for each product category using NORTHWND

Guys so as part of my job as a Data Support Analyst I am training up to become a software developer, my mentor gave me a group of test statements and this one seems way more advanced than anything I have done previously. The question is...
*
6) Write a subquery or common table expression to calculate total
orders for each product category. that will Write a query that will
bring back each product name, the total number of orders made for the
product and join to the subquery or CTE to calculate the percentage
of sales that product represents of its product category. For example,
if Category of Soaps has 2 products; Blue Soup and Red Soap, blue soup
had 40 orders and red soaps had 10 orders I would expect to see the
following rows: Product Name Total Orders % of Category Red
Soap 40 80%
Blue Soap 10 20%
*
So far I have managed to get the following but I'm struggling to progress past this...
;WITH [Products] (CategoryId, TotalNumberOfOrders)
AS (
SELECT p.CategoryId,
COUNT (OD.OrderID) as TotalNumberOfOrders
FROM [dbo].[Products] p
INNER JOIN [dbo].[Order Details] OD
ON p.ProductID=OD.ProductID
GROUP BY p.CategoryId )
SELECT * From Products
Any help would be fantastic! ( I'm using NORTHWND database btw)
I think what you need is
;WITH temp AS
(
SELECT p.CategoryId,
COUNT (DISTINCT OD.OrderID) as TotalNumberOfOrders
FROM [dbo].[Products] p
INNER JOIN [dbo].[Order Details] OD ON p.ProductID=OD.ProductID
GROUP BY p.CategoryId
)
SELECT p.ProductName,
Count(DISTINCT Od.OrderId) AS Total,
Count(DISTINCT Od.OrderId)*100/temp.TotalNumberOfOrders AS Percentage
FROM Products p
INNER JOIN [dbo].[Order Details] OD ON p.ProductId = OD.ProductId
INNER JOIN temp ON p.CategoryId = temp.CategoryId
GROUP BY p.ProductId, p.ProductName, temp.TotalNumberOfOrders
Remember Count(Distinct..) to count Order.
Using a sub-Query:
SELECT P.ProductName,
COUNT(OrderID) AS NumberOfOrders,
CAST((CAST(COUNT(OrderID) AS DECIMAL(9,2)) / CAST(Derived_Table.CNT AS
DECIMAL(9,2))) * 100 AS DECIMAL(9,2)) AS Percentage
FROM [Northwind].[dbo].[Order Details]
INNER JOIN dbo.Products AS P
ON [Order Details].ProductID = P.ProductID
INNER JOIN (SELECT COUNT(F.OrderID) AS CNT, P.CategoryID
FROM [Northwind].[dbo].[Order Details] F
INNER JOIN dbo.Products P
ON F.ProductID = P.ProductID
GROUP BY P.CategoryID) AS Derived_Table
ON P.CategoryID = Derived_Table.CategoryID
GROUP BY [Order Details].ProductID, P.ProductName, Derived_Table.CNT
ORDER BY [Order Details].ProductID

Trying to sum part of the rows

So I have three tables
Orders:
CustomerID,OrderID
Order Details;
OrderID,ProductId,UnitPrice,Quantity,Discount
And Products:
ProductID,ProductName
And I need to combine these 2 tables and create this one:
[Orderd Details].CustomersID,Products.ProductName,FORMULA
Formula is how much money people spent money on this product. So I think I have to sum UnitPrice* Quantity*(1-Discount) from every order for this product.
Sadly I have no idea how should I do it. The best I did is:
SELECT o.CustomerID,p.ProductName,SUM(od.Quantity*od.UnitPrice*(1-od.Discount)) as 'SKZ'
FROM Customers as c, Orders as o,[Order Details] as od,Products as p
WHERE (o.OrderID=od.OrderID AND p.ProductID=od.ProductID)
GROUP BY od.ProductID ORDER BY o.CustomerID;
But it doesn't work.
First, learn explicit JOIN syntax. Simple rule: Never use commas in the FROM clause.
Second, you should include all non-aggregated columns in the GROUP BY:
SELECT o.CustomerID, p.ProductName,
SUM(od.Quantity * od.UnitPrice * (1 - od.Discount)) as SKZ
FROM Orders as o JOIN
[Order Details] od
ON o.OrderID = od.OrderID JOIN
Products p
ON p.ProductID = od.ProductID
GROUP BY o.CustomerID, p.ProductName
ORDER BY o.CustomerID;

SQL Server : How to Select Sum Amount Spent for the Most Expensive Item by a Customer - Northwind DB

Actually question tells all; Lots of customers has many orders with for many items; I'm trying to display the total amount spent for the most expensive item ordered by that customers through the all orders given by that customer. I'm using Northwind DB and tables like Customers, Orders, Order Details, Products. I've the query below, I've tried to limit it by an aggregate function but SQL does not allow it on where clause. Any help?
select
p.ProductName,
c.ContactName,
od.ProductID,
MAX(od.UnitPrice)
SUM(od.UnitPrice*od.Quantity) as Total
from
Customers c
join
Orders o ON c.CustomerID = o.CustomerID
join
[Order Details] od on od.OrderID = o.OrderID
join
Products p on od.ProductID = p.ProductID
where
c.CustomerID in
group by
c.ContactName, p.ProductName, od.Quantity, od.ProductID
order by
MAX(od.UnitPrice) desc
I think the easiest way to solve this is by using a window function to get the highest priced product. The following query uses row_number() for this purpose:
select p.ProductName, c.ContactName, od.ProductID,
MAX(od.UnitPrice)
SUM(od.UnitPrice*od.Quantity) as Total
from Customers c join
(select od.*, o.CustomerId,
row_number() over (partition by o.CustomerId
order by od.UnitPrice desc) as seqnum
from [Order Details] od join
Orders o
on od.OrderId = o.OrderId
) od
on od.CustomerId = c.CustomerId and seqnum = 1 join
Products p
on od.ProductID = p.ProductID
group by c.ContactName, p.ProductName, od.ProductID
order by MAX(od.UnitPrice) desc;
Note that the joins have been rearranged a bit. You need the customer id to define the highest priced product in the subquery, so the subquery has the join to orders. You don't need the join in the outer query.

Getting data from a JOIN in SQL

Sorry for the messy name of the question, this is my first SQL one.
Does anyone know how to get the OrderID of an Order where the max quantity of a product was sold?
This is my code by far:
SELECT Products.ProductName, MAX([Order Details].Quantity), MAX(OrderID)
FROM Products
INNER JOIN [Order Details] ON Products.ProductID = [Order Details].ProductID
GROUP BY Products.ProductName
When I say MAX(OrderID) I get the Highest ID where the product was sold, not the actual ID where the Highest quantity of the product was sold.
This is my first question about SQL, Sorry for any lack of information, just tell me what is needed and I'll add it. Thanks in advance!
EDIT: I'm using SQL Server 2008
You can use analytical functions for this:
UPDATED
SELECT ProductName, Quantity, OrderID
FROM ( SELECT Products.ProductName, [Order Details].Quantity, OrderID,
ROW_NUMBER() OVER(PARTITION BY Products.ProductName ORDER BY [Order Details].Quantity DESC) Corr
FROM Products
INNER JOIN [Order Details] ON Products.ProductID = [Order Details].ProductID) A
WHERE Corr = 1
This way you will get only one record per Product, that means that if you have more than one Order with the same max quantity, you are only getting one as result. You can add more columns (order date for example) on the ORDER BY to choose the newest or oldest of those. If you want to get all the records that are tied on the quantity, then you can use RANK instead of ROW_NUMBER.
SELECT ProductName, Quantity, OrderID
FROM ( SELECT Products.ProductName, [Order Details].Quantity, OrderID,
RANK() OVER(PARTITION BY Products.ProductName ORDER BY [Order Details].Quantity DESC) Corr
FROM Products
INNER JOIN [Order Details] ON Products.ProductID = [Order Details].ProductID) A
WHERE Corr = 1
SELECT Products.ProductName, [Order Details].OrderID, [Order Details].Qty
FROM Products
INNER JOIN [Order Details] ON Products.ProductID = [Order Details].ProductID
WHERE [Order Details].Quantity = (SELECT MAX(p.Quantity) FROM [Order Details] p WHERE p.ProductID = Products.ProductID)
Note: this will give you multiple results for a single product, if you have multiple orders with max quantity ordered.