I want to find that how much number of products sold for particular category in northwind database? - sql

I have three main Tables
categories:
categoryID(primary Key)
CategoryName
Description.
OrderDetails
OrderID (primary Key)
ProductID
Quantity
Products
productId (Primary Key)
ProductName
CategoryID
Now I have to write a query to get number of products sold for particular category?
here is my attempt
SELECT Products.ProductID,
Products.CategoryID,
SUM(OrderDetails.Quantity)
FROM Products
LEFT INNER JOIN OrderDetails
ON (SELECT OrderDetails.Quantity,
orderDetails.ProductID,
categories.categoryName
FROM orderDetails
LEFT INNER JOIN Categories
ON categories.categoryID=products.CategoryId
)
ON Products.ProductId = OrderDetaqils.ProductId
i am not getting any answer close to my requirement.its not correct
please give me the solution if possible
It would be great help if you can give me the solution. If you required any additional details please let me know

here is the SQL query
SELECT Product.ProductID,
sum(Quantity) as TotalSoldAmount,
categories.CategoryID,
CategoryName
FROM OrderDetails
-- INNER JOIN over all 3 Tables
INNER JOIN Product ON Product.ProductID = OrderDetails.ProductID
INNER JOIN categories ON categories.CategoryID = Product.CategoryID
-- we need to group our result because we used sum()
GROUP BY categories.CategoryID,
CategoryName,
Product.ProductID
and her the sqlfiddle as prove

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

Display product with minimum units sold in SQL

I've been tasked with the following Query to design:
"Out of the products that sold units in 2019 (that is, that sold at least one unit), we want to know the product that sold the least number of units. Your table must show:
 Product ID
 Product name
 Product’s category name "
I have included a screenshot of the database.
I am, in fact, able to retrieve the value corresponding to the minimum units sold [95 in this case], but cannot also display the corresponding product name to that value in MS Access.
Using the following code displays the correct minimum value:
SELECT MIN(UnitsSold)
FROM
(SELECT Products.ProductID, ProductName, Categories.CategoryID, CategoryName, SUM(Quantity) AS UnitsSold
FROM Orders, OrderDetails, Products, Categories
WHERE Orders.OrderID = OrderDetails.OrderID AND OrderDetails.ProductID = Products.ProductID And Products.CategoryID = Categories.CategoryID AND OrderDate BETWEEN #01/01/2019# AND #12/31/2019#
GROUP BY Products.ProductID, ProductName, Categories.CategoryID, CategoryName
HAVING SUM(Quantity) >= 1);
But when I try to also display that product with this modification:
SELECT MIN(UnitsSold, Products.ProductID, ProductName
FROM
(SELECT Products.ProductID, ProductName, Categories.CategoryID, CategoryName, SUM(Quantity) AS UnitsSold
FROM Orders, OrderDetails, Products, Categories
WHERE Orders.OrderID = OrderDetails.OrderID AND OrderDetails.ProductID = Products.ProductID And Products.CategoryID = Categories.CategoryID AND OrderDate BETWEEN #01/01/2019# AND #12/31/2019#
GROUP BY Products.ProductID, ProductName, Categories.CategoryID, CategoryName
HAVING SUM(Quantity) >= 1);
I am met with the error:
Your query does not include the specified expression 'ProductID' as part of an aggregate function
Why not just use ORDER BY and TOP 1?
SELECT TOP (1)
p.ProductID,
ProductName,
c.CategoryName,
FROM
Orders o
INNER JOIN OrderDetails od ON o.OrderID = od.OrderID
INNER JOIN Products p ON od.ProductID = p.ProductID
INNER JOIN Categories c ON p.CategoryID = c.CategoryID
WHERE OrderDate BETWEEN #01/01/2019# AND #12/31/2019#
GROUP BY
p.ProductID,
ProductName,
c.CategoryName
HAVING SUM(Quantity) >= 1
ORDER BY SUM(Quantity) DESC
Notes:
always use explicit joins (with the ON keyword) instead of implicit joins (with commas in the FROM clause), whose syntax is harder to follow and has fallen out of favor more than 20 years ago
table aliases make the query easier to write and read; also, in a multi-table query, you want to qualify all column names (there are a few table prefixes missing in your query).

SQL Count with a Join

select product_name, product_order.Count(*)
From product Join product_order
ON product.product_id = product_order.product_id
where product.product_id = product_order.product_id;
I have been working on this query for an hour and can't seem to get it to work. All I need to do is take the product from one table match it to how many times it was ordered in another. Then display the product in one column and how many times it was ordered in the next.
This should be as simple as:
select product_name,
count(product_order.product_id)
From product left join product_order
on product.product_id = product_order.product_id
group by product_name
I used a left join and counted on product_order.product_id so products that have not been ordered will still display, with a count of zero.
This is how I would do it:
select p.product_name,
(select count(*) from product_order po where p.product_id = po.product_id) times_ordered
from product p
Alternatively, you could use a group by statement:
select p.product_name,
count(po.product_id)
from product p,
product_order po
where p.product_id = po.product_id(+)
group by p.product_name

Conditionally joining tables

I want to create conditional join to a table in my T-SQL query. Tables used in this example are from Northwind database (with only one additional table ProductCategories)
Table Products and table Categories have many-to-many relationship, hence table ProductCategories comes into picture.
I need the sum of Quantity column on table OrderDetails for each of the products falling under certain category. So I have a query like one below
Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
Join OrderDetails od On od.ProductID = p.ProductID
Join ProductCategories pc On pc.ProductID = p.ProductID
And pc.CategoryID = #CategoryID
Group By p.ProductName
#CategoryID is an optional parameter. So in case it's not supplied, the join to table ProductCategories will not be required
and query should look like one below
Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
Join OrderDetails od On od.ProductID = p.ProductID
Group By p.ProductName
I want to achieve this without repeating the whole query with If conditions (as below)
If #CategoryID Is Null
Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
Join OrderDetails od On od.ProductID = p.ProductID
Group By p.ProductName
Else
Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
Join OrderDetails od On od.ProductID = p.ProductID
Join ProductCategories pc On pc.ProductID = p.ProductID
And pc.CategoryID = #CategoryID
Group By p.ProductName
This is simplified version of the query which has many other tables and conditions like ProductCategories. And will require multiple multiple If conditions and repetition of the query. I have also tried dynamically generating the query. It works but query is not readable at all.
Any solutions?
Thank you.
Try this, if you'll use properly parametrized query - there will be no performance impact but may be gain:
Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
Join OrderDetails od On od.ProductID = p.ProductID
WHERE #CategoryID IS NULL OR EXISTS (SELECT * FROM ProductCategories WHERE CategoryID = #CategoryID AND ProductID = p.ProductID)
Group By p.ProductName
Actually
in your query if there can be multiple rows in ProductCategories for one row in OrderDetails - then you get duplicates of od.Quantity in your SUM - is it an intended behavior?
I believe you can left join the tables vs the implicit inner join you are doing.
In an inner join it matches the key on the source table with each instance of the key on the destination table.
Each instance of a match on the destination table generates a set of rows displaying the
match types.
With an outer join it will display the source row EVEN IF there is no matching row in the other table. If there is it will do essentially the same as an inner join and you'll get a row back for each instance of match. So you're getting the data you need when it's available and not getting what data is unavailable.
Take this as an example
select * from Products
Left join ProductAndCategory on ProductAndCategory.ProductID = Products.ProductID
left join Categories on Categories.CategoryID = ProductAndCategory.CategoryID
Where I have a simple Product table with a ProductID and a ProductName a ProductAndCategory table with a ProductID and a CategoryID and a Categories table with a CategoryID and a CategoryName
It will show the rows that have categories with the joined categories and the rows that don't have categories will just show the one row with null for the values that don't exist.
I'm not very familiar with T-SQL so I don't know if this will cut it but in mysql you could do something like
Select p.ProductName, Sum(od.Quantity) As Qty
From Products p
Join OrderDetails od On od.ProductID = p.ProductID
Join ProductCategories pc On pc.ProductID = p.ProductID
And pc.CategoryID = if(#CategoryID is null , pc.CategoryID, #CategoryId)
Group By p.ProductName
Yes and if() still remains but just "one query", if that's what you're looking for.
At the same time, you say you were able to dynamically generate a single query. If so is the readability that much of an issue? If your generated query was more performant over what I suggested above I'd go with that. It's generated; you won' be manually tweaking/reading the result.

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