SQL Query - Understanding the Syntax - sql

I want to display greatest selling product by quantity
Product Table
ProductID ProductName
1 AA
2 BB
3 CC
[Order Details] Table
OrderID ProductID Quantity DateOfOrder
1 1 10 SomeDate
2 1 100 ,,
3 2 15 ,,
4 1 15 ,,
5 2 20 ,,
6 2 30 ,,
7 1 100 ,,
Expected Output
Product By Quantity AA
Because sum(quantity)= 225
I used:
select 'Product By Quantity' + ProductName
from
Products
where ProductID in
(select
ProductID
from
[Order Details] det
where Quantity=
(
select max(SUM(Quantity))
from [Order Details] od
where
od.ProductID=det.ProductID
)
)
I got error : "Cannot perform an aggregate function on an expression containing an aggregate or a subquery"
Please explain me why the syntax fails here so that in future i will write appropriate query by
knowing the correct syntax.Also give me the correct query.
Thank you everybody in advance.
Edit
I was trying for the following query
SELECT 'Best Selling Product'+ProductName
FROM
Products
WHERE ProductID =
(
SELECT ProductID
FROM [Order Details]
GROUP BY ProductID
HAVING SUM(Quantity) = (
SELECT MAX(SQ)
FROM (
SELECT SUM(Quantity) as SQ
FROM [Order Details]
GROUP BY ProductID
) AS OD))

I think this is what you're trying to get to:
select top 1 p.product_name, sum(od.quantity) as total_quantity
from products p
inner join [order details] od
on p.productid = od.productid
group by p.productid, p.product_name
order by total_quantity desc

Try this:
select 'Product By Quantity' + ProductName from Products p
join
(
select top 1 sum(Quantity) sq, od.ProductId
from [Order Details] od
group by od.ProductId
order by 1 desc
) bsp on p.productid = bsp.ProductId
bsp stands for Best Selling Product

looks like select max(SUM(Quantity)) is wrong. The maximum of the sum doesn't have any meaning. Did you mean max(Quantity)?

Try this:
SELECT TOP 1
SUM(o.Quantity)
,p.ProductName
FROM [Order Details] AS o
INNER JOIN [Products] AS p ON p.ProductID = o.ProductID
GROUP BY p.ProductID
,p.ProductName
ORDER BY SUM(o.Quantity) DESC

Related

How do carry out arithmetic functions using join in SQL?

Products
productid
productname
unitprice
1
potato
5
OrderDetails
ordered
productid
unitprice
discount
1
1
5
.15
I am trying to list all products using the highest price (which would be without the discount). So I need to calculate the price without the discount and list that as unitprice alongside the productid and productname.
SELECT products.productid, products.productname, orderdetails.unitprice
FROM products
INNER JOIN orderdetails ON products.productid = orderdetails.productid
WHERE orderdetails.unitprice =
(SELECT (orderdetails.unitprice/( 1- orderdetails.discount))
AS highest_unitprice
FROM orderdetails);
I get this error:
single-row subquery returns more than one row
How can I fix this?
Maybe this will compile->
SELECT *
FROM
(
SELECT products.productid, products.productname, orderdetails.unitprice,
ROW_NUMBER()OVER(PARTITION BY orderdetails.productid ORDER BY orderdetails.unitprice) AS PriceIndex
FROM products
INNER JOIN orderdetails ON products.productid = orderdetails.productid
)AS X
WHERE
PriceIndex=1

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

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

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

SQL Change output of column if duplicate

I have a table which has rows for each product that a customer has purchased. I want to output a column from a SELECT query which shows the time it takes to deliver said item based on whether the customer has other items that need to be delivered. The first item takes 5 mins to deliver and all subsequent items take 2 mins to deliver e.g. 3 items would take 5+2+2=9 mins to deliver.
This is what I have at the moment(Using the Northwind sample database on w3schools to test the query):
SELECT orders.customerid,
orders.orderid,
orderdetails.productid,
CASE((SELECT Count(orders.customerid)
FROM orders
GROUP BY orders.customerid))
WHEN 1 THEN '00:05'
ELSE '00:02'
END AS DeliveryTime
FROM orders
LEFT JOIN orderdetails
ON orderdetails.orderid = orders.orderid
This outputs '00:05' for every item due to the COUNT in my subquery(I think?), any ideas on how to fix this?
Try this
SELECT orders.customerid,
orders.orderid,
orderdetails.productid,
numberorders,
2 * ( numberorders - 1 ) + 5 AS deleveryMinutes
FROM orders
INNER JOIN (SELECT orders.customerid AS countId,
Count(1) AS numberOrders
FROM orders
GROUP BY orders.customerid) t1
ON t1.countid = orders.customerid
LEFT JOIN orderdetails
ON orderdetails.orderid = orders.orderid
ORDER BY customerid
Gregory's answer works a treat and here's my attempts
-- Without each product line item listed
SELECT O.CustomerId,
O.OrderId,
COUNT(*) AS 'NumberOfProductsOrderd',
CASE COUNT(*)
WHEN 1 THEN 5
ELSE (COUNT(*) * 2) + 3
END AS 'MinutesToDeliverAllProducts'
FROM Orders AS O
INNER JOIN OrderDetails AS D ON D.OrderId = O.OrderId
GROUP BY O.CustomerId, O.OrderId
-- Without each product line item listed
SELECT O.CustomerId,
O.OrderId,
D.ProductId,
CASE
WHEN P.ProductsInOrder = 1 THEN 5
ELSE (P.ProductsInOrder * 2) + 3
END AS 'MinutesToDeliverAllProducts'
FROM Orders AS O
INNER JOIN OrderDetails AS D ON D.OrderId = O.OrderId
INNER JOIN (
SELECT OrderId, COUNT(*) AS ProductsInOrder
FROM OrderDetails
GROUP BY OrderId
) AS P ON P.OrderId = O.OrderId
GROUP BY O.CustomerId,
O.OrderId,
D.ProductId,
P.ProductsInOrder
Final code is below for anyone interested:
SELECT O.CustomerId,
O.OrderId,
Group_Concat(D.ProductID) AS ProductID,
CASE COUNT(*)
WHEN 1 THEN 5
ELSE (COUNT(*) * 2) + 3
END AS 'MinutesToDeliverAllProducts'
FROM Orders AS O
INNER JOIN OrderDetails AS D ON D.OrderId = O.OrderId
GROUP BY O.CustomerId

Calculating the SUM of (Quantity*Price) from 2 different tables

I have two tables as follows
PRODUCT table
Id | Name | Price
And an ORDERITEM table
Id | OrderId | ProductId | Quantity
What I'm trying to do is, calculate the subtotal price for each product (Quantity*Price) then SUM the TOTAL value for the entire order..
I'm trying something like this
SELECT Id, SUM(Quantity * (select Price from Product where Id = Id)) as qty
FROM OrderItem o
WHERE OrderId = #OrderId
But of course that doesn't work :)
Any help appreciated!
EDIT: I only want to show the grand total for the entire order, so basically the sum of Quantity*Price for every row in OrderItem. Here's some sample data.
Sample Data
TABLE Product
Id Name Price
1 Tomatoes 20.09
4 Cucumbers 27.72
5 Oranges 21.13
6 Lemons 20.05
7 Apples 12.05
Table OrderItem
Id OrderId ProductId Quantity
151 883 1 22
152 883 4 11
153 883 5 8
154 883 6 62
M
Use:
SELECT oi.orderid,
SUM(oi.quantity * p.price) AS grand_total,
FROM ORDERITEM oi
JOIN PRODUCT p ON p.id = oi.productid
WHERE oi.orderid = #OrderId
GROUP BY oi.orderid
Mind that if either oi.quantity or p.price is null, the SUM will return NULL.
i think this - including null value = 0
SELECT oi.id,
SUM(nvl(oi.quantity,0) * nvl(p.price,0)) AS total_qty
FROM ORDERITEM oi
JOIN PRODUCT p ON p.id = oi.productid
WHERE oi.orderid = #OrderId
GROUP BY oi.id
I think this is along the lines of what you're looking for. It appears that you want to see the orderid, the subtotal for each item in the order and the total amount for the order.
select o1.orderID, o1.subtotal, sum(o2.UnitPrice * o2.Quantity) as order_total from
(
select o.orderID, o.price * o.qty as subtotal
from product p inner join orderitem o on p.ProductID= o.productID
where o.orderID = #OrderId
)as o1
inner join orderitem o2 on o1.OrderID = o2.OrderID
group by o1.orderID, o1.subtotal
select orderID, sum(subtotal) as order_total from
(
select orderID, productID, price, qty, price * qty as subtotal
from product p inner join orderitem o on p.id = o.productID
where o.orderID = #orderID
) t
group by orderID
I had the same problem as Marko and come across a solution like this:
/*Create a Table*/
CREATE TABLE tableGrandTotal
(
columnGrandtotal int
)
/*Create a Stored Procedure*/
CREATE PROCEDURE GetGrandTotal
AS
/*Delete the 'tableGrandTotal' table for another usage of the stored procedure*/
DROP TABLE tableGrandTotal
/*Create a new Table which will include just one column*/
CREATE TABLE tableGrandTotal
(
columnGrandtotal int
)
/*Insert the query which returns subtotal for each orderitem row into tableGrandTotal*/
INSERT INTO tableGrandTotal
SELECT oi.Quantity * p.Price AS columnGrandTotal
FROM OrderItem oi
JOIN Product p ON oi.Id = p.Id
/*And return the sum of columnGrandTotal from the newly created table*/
SELECT SUM(columnGrandTotal) as [Grand Total]
FROM tableGrandTotal
And just simply use the GetGrandTotal Stored Procedure to retrieve the Grand Total :)
EXEC GetGrandTotal