sql issue to query product name - sql

I am new to SQL , I have been looking for on line resources but have not find anything yet to solve my problem. Basically i have three tables below:
ORDERTBL(ORDERID,ORDERDATE,ORDERSTATUS),
PRODUCT(PRODUCTID,PRODUCT_NAME),
ORDERLINKPRODUCTS(ORDERID,PRODUCTID,QUANTITY,ORDERLINKPRODUCTID)
I want to get all the product name from the products tables for a specific order which i should query from ORDERLINKPRODUCTS since it contains all the orders.
for instance please find test data available in 3 tables:
Table ORDERTBL:
ORDERID=1,ORDERDATE= 24May, ORDERSTATUS=Process
Table PRODUCTS:
PRODUCID =1 PRODUCT_NAME = spoon PRODUCID =2 PRODUCT_NAME = soap
Table :ORDERLINKPRODUCTS:
ORDERID=1 PRODUCTID = 1 QUANTITY=3 ORDERLINKPRODUCTID=1 ORDERID=1 PRODUCTID = 2 QUANTITY=1 ORDERLINKPRODUCTID=2
I am trying to make a select statements that display all the product name of an order. For instance display all product name of orderid=1 which will return spoon,soap.
Any suggestion how to do it please?
Thanks in advance.

You should use JOIN keyword in SQL to join the three tables to be able to access PRODUCTNAME and show that table data. More about Join clause
SELECT prod.PRODUCT_NAME
FROM ORDERTBL ord
INNER JOIN ORDERLINKPRODUCTS link ON ord.ORDERID = link.ORDERID
INNER JOIN PRODUCT prod ON link.PRODUCTID = prod.PRODUCTID
WHERE ord.ORDERID = 1
SQLfiddle Demo

You can find orders with products ilsted using this
SELECT O.ORDERID, RTRIM(
XMLAGG(XMLELEMENT(e, P.PRODUCT_NAME ||',') ORDER BY O.ORDERID).EXTRACT('//text()'), ',') as Products
FROM ORDERTBL O
INNER JOIN ORDERLINKPRODUCTS L
ON O.ORDERID = L.ORDERID
INNER JOIN PRODUCT P
ON L.PRODUCTID = P.PRODUCTID
GROUP BY O.ORDERID
and products listed with its quantity using this:
SELECT O.ORDERID, RTRIM(
XMLAGG(XMLELEMENT(e, P.PRODUCT_NAME || '(' || L.QUANTITY || '),') ORDER BY O.ORDERID).EXTRACT('//text()'), ',') as Products
FROM ORDERTBL O
INNER JOIN ORDERLINKPRODUCTS L
ON O.ORDERID = L.ORDERID
INNER JOIN PRODUCT P
ON L.PRODUCTID = P.PRODUCTID
GROUP BY O.ORDERID
You can add WHERE clause clause to filted orders as you whish.
SQL FIDDLE DEMO

Related

Using MS Access SQL - how would I select the top 5 food items by group (restaurant) based on the number of orders?

Relationship Diagram
What I want to be able to do is return a query that shows the top 5 items/products on the menu for each of the 3 restaurants in the dataset. I've attached an example of the relationship diagram for some more context. The columns I would like to see in the query are:
RestaurantName
ItemName
NumberofOrders (alias column)
This is what I have at the moment but it doesn't work as expected for the top 5.
SELECT RestaurantName, ItemName, COUNT(Orders.OrderNumber) AS NumberofOrders
FROM ((((Restaurants INNER JOIN
Orders ON Restaurants.RestID = Orders.RestID) INNER JOIN
OrderDetails ON Orders.OrderNumber=OrderDetails.OrderNumber) INNER JOIN
Products ON OrderDetails.ItemID = Products.ItemID) INNER JOIN
FoodType ON Products.ProdTypeID = FoodType.ProdType)
WHERE ItemName IN
(SELECT TOP 5 ItemName
FROM Products
WHERE ItemName IS NOT NULL)
GROUP BY RestaurantName, ItemName
ORDER BY COUNT(Orders.OrderNumber) DESC;
This just repeats the same 5 items across all the restaurants. Any point in the right direction would be awesome.
EDIT 1:
Based on a response I got yesterday, I have made some amendments to the code. This the query is returning the full list, as though ignoring the top 5 in the subquery. I can see all the items are sorted by Total Orders (I have also changed the formula for this) Any ideas what I am doing wrong here?
SELECT RestaurantName, ItemName, SUM(Quantity)*COUNT(Orders.OrderNumber) AS TotalOrders
FROM ((((Restaurants INNER JOIN
Orders ON Restaurants.RestID = Orders.RestID) INNER JOIN
OrderDetails ON Orders.OrderNumber=OrderDetails.OrderNumber) INNER JOIN
Products ON OrderDetails.ItemID = Products.ItemID) INNER JOIN
FoodType ON Products.ProdTypeID = FoodType.ProdType)
WHERE ItemName IN
(SELECT TOP 5 p2.ItemName
FROM Products AS p2
WHERE p2.ItemName = Products.ItemName
GROUP BY p2.ItemName
ORDER BY COUNT(*) DESC)
GROUP BY RestaurantName, ItemName
ORDER BY RestaurantName, SUM(Quantity) DESC;
Thanks
You want a correlated subquery:
WHERE ItemName IN (SELECT TOP 5 p2.ItemName
FROM Products as p2
WHERE p2.RestaurantName = products.RestaurantName
GROUP BY p2.ItemName
ORDER BY COUNT(*) DESC
)
It seems really odd to me that a table called products would have a column called RestaurantName. But you claim that your query works and it has the same reference.
Your filter in the outer WHERE is only using the ItemName field. For your purpose it should contain both fields.
Like so:
SELECT
RestaurantName,
ItemName,
COUNT(Orders.OrderNumber) AS NumberofOrders
FROM Restaurants
INNER JOIN Orders ON Restaurants.RestID = Orders.RestID
INNER JOIN OrderDetails ON Orders.OrderNumber=OrderDetails.OrderNumber
INNER JOIN Products ON OrderDetails.ItemID = Products.ItemID
INNER JOIN FoodType ON Products.ProdTypeID = FoodType.ProdType
WHERE (RestaurantName, ItemName) IN
(SELECT TOP 5 RestaurantName, ItemName
FROM Products
WHERE RestaurantName IS NOT NULL)
GROUP BY RestaurantName, ItemName
ORDER BY COUNT(Orders.OrderNumber) DESC;

How to create a function that totals an order with several items?

I need to create a function which will return the total of an order. I've been given three tables with the following variables
Table 1 - Order
Order_ID
Date_Placed
Date_Fulfilled
Table 2 - Order Product
Order_ID
Product_ID
Product_Quantity
Table 3 - Product
Product_ID
Price
I'm struggling to put together a coherent function. Any help would be greatly appreciated.
I've already attempted to set up the function with joins between both tables, but am unable to figure out where I should be putting my equation.
BEGIN
SELECT order.order_id, SUM(product.price * order_item.quantity)
FROM `order`
JOIN `order_item` ON order.order_id = order_product.order_id
JOIN `product` ON order_product.product_id = product.product_id;
END $$
You might be surprised, but the orders table is not needed for this query. You can just aggregate off the other two tables:
SELECT oi.order_id, SUM(p.price * oi.quantity)
FROM order_item oi JOIN
product p
ON po.product_id = p.product_id
GROUP BY oi.order_id;
You'll need to take your select statement, and group it by your order.order_id. That way you'll have one row per order, with the sum total of that order.
SELECT order.order_id, SUM(product.price * order_item.quantity) as total_price
FROM `order`
JOIN `order_item` ON order.order_id = order_product.order_id
JOIN `product` ON order_product.product_id = product.product_id
GROUP BY order.order_id
this will work:
SELECT order.order_id, SUM(product.price * order_item.quantity)
FROM order o,
JOIN order_item oi,
JOIN product p where
o.order_id = oi.order_id and
oi.product_id = p.product_id
group by order_product.product_id = product.product_id;

Insufficient output from SQL query

I'm using the northwind db: http://dev.assets.neo4j.com.s3.amazonaws.com/wp-content/uploads/Northwind_diagram.jpg
I have to output all orders placed by CustomerID ALFKI with more than one unique product. I get the correct orders out, but I can't figure out why it's only printing one product name per order.
My query:
SELECT a.OrderID, p.ProductName
FROM Products p
INNER JOIN 'Order Details' a
ON (p.ProductID = a.ProductID)
INNER JOIN Orders b
ON (a.OrderID = b.OrderID)
WHERE (b.CustomerID = 'ALFKI')
GROUP BY a.OrderID
HAVING COUNT(DISTINCT a.ProductID) > 1
You need the GROUP BY and HAVING to be part of a subquery, with your primary query selecting the detail using the list of OrderIDs returned from the subquery as filter criteria. Try the following syntax for T-SQL:
SELECT
a.OrderID,
p.ProductName
FROM
Products p
INNER JOIN [Order Details] a
ON (p.ProductID = a.ProductID)
INNER JOIN Orders b
ON (a.OrderID = b.OrderID)
WHERE
a.OrderID IN
(
SELECT a.OrderID
FROM [Order Details] a
INNER JOIN Orders b
ON (a.OrderID = b.OrderID)
WHERE (b.CustomerID = 'ALFKI')
GROUP BY a.OrderID
HAVING COUNT(DISTINCT a.ProductID) > 1
)

Joining over an interim table SQL Server

I have a table of rules for pricing. I am retrieving the max discount for each ProductTypeID, which indicates which type a product is, using this query :
SELECT MAX(discount) as BiggestDiscount, ProductTypeID FROM dbo.SellingPriceRules
WHERE ProductTypeID is not null
GROUP by ProductTypeID
ORDER BY ProductTypeID
This works perfectly, however I need to expand on this and, for a list of ProductIDs retrieve my biggest discount. So I need to find what ProductTypeID each ProductID belongs to and check my SellPriceRules database for the max discount for this ProductTypeID.
So, in my Discounts table, I have :
ProductID, Margin
And in my Products Table I have :
ProductID, ProductTypeID
In order to get the ProductTypeID of each product, I have :
select * from Discounts m
INNER JOIN Product p on p.ProductID = m.ProductID
WHERE ProductTypeID is not null
I am now struggling with joining these two queries together. I simply want to get the max discount for each product in the discounts table and subtract this from my margin. How can I join these two retirevals together?
Thanks very much
You have all the logic correct. You just need the syntax of embedding one query inside another.
SELECT
p.ProductID,
p.ProductTypeID,
m.Margin,
d.BiggestDiscount,
m.Margin - d.BiggestDiscount AS AdjustedMargin
FROM Product p
INNER JOIN Discounts m ON (p.ProductID = d.ProductID)
INNER JOIN (
SELECT
ProductTypeID,
MAX(discount) as BiggestDiscount
FROM SellingPriceRules
GROUP BY ProductTypeID
) d ON (p.ProductTypeID = d.ProductTypeID)
WHERE p.ProductID IS NOT NULL
Generally, you can use CTE in such situations. Something like this:
;WITH current_discounts (BiggestDiscount, ProductTypeID)
AS (
SELECT MAX(discount) as BiggestDiscount, ProductTypeID FROM dbo.SellingPriceRules
WHERE ProductTypeID is not null
GROUP by ProductTypeID
ORDER BY ProductTypeID
)
SELECT
m.ProductID,
m.Margin - c.BiggestDiscount
FROM Discounts m
INNER JOIN Product p ON p.ProductID = m.ProductID
INNER JOIN current_discounts c ON p.ProductTypeID = c.ProductTypeID
You can try something like this :
select *, Margin-BiggestDiscount from Discounts m
INNER JOIN Product p on p.ProductID = m.ProductID AND p.ProductTypeID is not null
inner join (
SELECT MAX(discount) as BiggestDiscount, ProductTypeID
FROM dbo.SellingPriceRules
GROUP by ProductTypeID) as r on p.ProductTypeID = r.ProductTypeID
Use correlated subquery
SELECT m.ProductID, m.Margin, p.ProductTypeID,
m.Margin - (SELECT MAX(discount)
FROM dbo.SellingPriceRules
WHERE ProductTypeID = p.ProductTypeID)
FROM Discounts m INNER JOIN Product p on p.ProductID = m.ProductID
WHERE p.ProductTypeID IS NOT NULL
The execution plan especially for #Annon

Fetch data from more than one tables using Group By

I am using three tables in a PostgreSql database as:
Customer(Id, Name, City),
Product(Id, Name, Price),
Orders(Customer_Id, Product_Id, Date)
and I want to execute a query to get from them "the customers that have have ordered at least two different products alnong with the products". The query I write is:
select c.*, p.*
from customer c
join orders o on o.customer_id = c.id
join product p on p.id = o.product_id
group by (c.id)
having count(distinct o.product_id)>=2
It throws the error:
"column "p.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: select c.*, p.*".
However if I remove the the p.* from select statement (assuming that I one does not want the products, only the customers), it runs fine. How can I get the products as well?
Update: Having ordered two or more products, a customer must appear on the output as many times as its product he has ordered. I want as output a table with 5 columns:
Cust ID | Cust Name | Cust City | Prod ID | Prod Name | Prod Price
Is it possible in SQL given that group by should be used? Shoul it be used on more than one columns on different tables?
Try this out :
SELECT distinct c.* ,p.*
FROM Customer c
JOIN
(SELECT o.customer_id cid
FROM Product P
JOIN Orders o
ON p.id= o.product_id
GROUP BY o.customer_id
HAVING COUNT(distinct o.product_id)>=2) cp
ON c.id =cp.cid
JOIN Orders o
on c.id=o.customer_id
JOIN Product p
ON o.product_id =p.id
I hope it solves your problem.
I think you can use following query for this question -
SELECT C1.*, p1.*
FROM Customer C1
JOIN Orders O1 ON O1.Customer_Id = C1.Id
JOIN Product P1 ON P1.Id = O1.Product_Id
WHERE C1.Id IN (SELECT c.Id
FROM Customer c
JOIN Orders o ON o.Customer_Id = c.Id
GROUP BY (c.Id)
HAVING COUNT(DISTINCT o.Product_Id) >= 2)