Get the min() value from columns where duplicates are associated with ids - sql

So, to simplify my problem is as follows:
A. I pass in CustomerID, there can be multiple Orders per Customer. I need to find the minimum ProductID per Order per Customer.
B. Once that is complete, I need run the main query (to return the dataset) in which I would like to display all the Orders, along with Category and Code (per Product). The result should display NULL for Product, Category and Code where the ProductID <> the ProductID found in Part A.
Thanks
(All these are separate tables with foreign keys. I can handle the joins, it's just the "minimum ProductID per Order per Customer" thing that's throwing me.)

You did not provide much information about your specific database schema, so an exact answer is hard to provide. Basically, you want to use a combination of MIN and Group By (and perhaps a join or two depending on your schema).
The following provides a rough example:
select min(ProductID) from Orders o
inner join Customers c
on o.CustomerID = c.CustomerID
group by (productID)
having c.CustomerID = <customer id value>
Regards,

Related

What's the use of this WHERE clause

this is an answer to the question : We need a list of customer IDs with the total amount they have ordered. Write a SQL statement to return customer ID (cust_id in the Orders table) and total_ordered using a subquery to return the total of orders for each customer. Sort the results by amount spent from greatest to the least. Hint: you’ve used the SUM() to calculate order totals previously.
SELECT prod_name,
(SELECT Sum(quantity)
FROM OrderItems
WHERE Products.prod_id=OrderItems.prod_id) AS quant_sold
FROM Products
;
So there is this simple code up here, and I know that this WHERE clause is comparing two columns in two different tables. But since We are calculating the SUM of that quantity, why do need that WHERE clause exactly. I really couldn't get it. Why the product_id exactly and not any other column ( p.s: the only shared column between those two tables is prod_id column ) I am still a beginner. Thank you!
First you would want to know the sum for each product - so need to adjust the subquery similar to this:
(SELECT prod_id, Sum(quantity) qty
FROM OrderItems
group by prod_id
) AS quant_sold
then once you know how much for each product, then you can link that
SELECT prod_name,
(SELECT prod_id, Sum(quantity) qty
FROM OrderItems
group by prod_id
) AS quant_sold
FROM Products p
WHERE p.prod_id = quant_sold.prod_id
Run it without the where clause and compare the results. You'll learn a lot that way. specifically focus on two different product Ids ensuring they both have order items and quantities.
You have two different tables involved. There are multiple products. You don't want the sum of all orders on each product; which is what you would get without the where clause. So the where clause correlates the two tables ensuring you only SUM the quantity of each order item for each product between the tables. Personally, I'd use a join, sum, and a group by as I find it easier to read and I'm not a fan of sub selects in the select of another query; but that's me.
SELECT prod_name,
(SELECT Sum(quantity)
FROM OrderItems
WHERE Products.prod_id=OrderItems.prod_id) AS quant_sold
FROM Products
Should be the same as:
SELECT prod_name, Sum(coalesce(P.quantity,0))
FROM Products P
LEFT JOIN orderItems OI
on P.prod_id=OI.prod_id
GROUP BY Prod_Name
'Notes
the above is untested.
a left join is needed because all products should be listed and if a product doesn't have an order, the quantity would be zero.
if we use an inner join, the product would be excluded.
We use coalesce because you'd have a "Null" quantity instead of zero for such lines without an order item.
as to which is "right" well it depends and varies on different cases. each has it's own merits and in different cases, one will perform better than another, and in a different case, vice-versa. See --> Join vs. sub-query
As an example:
Say you have Products A & B
"A" has Order Item Quantities of 1 & 2
"B" has order item Quantities of 10 & 20
If we don't have the where clause every result record would have qty 33
If we have the where product "A" would have 3
product "B" would have qty 30.

SQL Server need to find suppliers who supply the most different products

I have two tables I need information from, Products and Suppliers. Both these tables have a SupplierID column I am trying to use to join them together to retrieve the right info.
The output I need is SupplierID and ContactName from the Suppliers table. The correct output should contain only two suppliers, so I attempted something like this, but ran into a conversion error converting nvarchar value to a data type int. I am not supposed to count how many products they supply but aggregate functions seem like the best method to me.
SELECT TOP 2 ContactName, COUNT(Products.SupplierID) AS Supply
FROM Products
LEFT JOIN Suppliers ON Suppliers.ContactName = Products.SupplierID
GROUP BY Products.SupplierID, Suppliers.ContactName
ORDER BY Supply;
I have tried many different queries but none will work. I am confused on how to join these tables without running into errors. All the products have a unique ProductID as well. The correct output should look something like this:
7 John Smith
12 John Sample
Both these tables have a SupplierID column I am trying to use to join them together to retrieve the right info
If so, you should be joining on that column accross tables.
Also, it is a good practice to use table aliases and prefix each column with the table it belongs to.
Another remark is that if you want suppliers that sell the most different products, then you want to order by descending count (not ascending).
Finally, if you want to left join, then you should start from the suppliers and then bring in the products, not the other way around.
Consider:
select top 2
s.SupplierID,
s.ContactName,
COUNT(*) as Supply
from Suppliers s
left join Products p on p.SupplierID = s.SupplierID
group by s.SupplierID, s.ContactName
order by Supply desc;
You're currently joining on two different fields:
on Suppliers.ContactName = Products.SupplierID
Presumably this should be as follows?
on Suppliers.SupplierID = Products.SupplierID

How to SQL distinct on only one column

I'm trying to apply DISTINCT on only one column.
The question is:
Who is ordering equipment where the description begins with "tennis" or "volleyball".
Include:
Customer number,
Stock number, and
Description
Do not repeat any rows.
This is what the tables look like: Items, Stock, Orders
This is my code:
select distinct
orders.customer_num, stock.stock_num, stock.description
from
orders
join
items on items.order_num = orders.order_num
join
stock on stock.stock_num = items.stock_num
where
stock.description like 'tennis%'
or stock.description like 'volleyball%';
The result is:
But I'm trying to get no repeating numbers on the CUSTOMER_NUM column.
Thank you..
There is a possibility that your join condition is wrong.please try joining item table to customer table with condition as items.customer_num =customer.customer_num .I am not sure whether it will work as we dont have correct data of these tables.
I'm not sure you'll see this, but I don't believe the rows aren't repeating. Look at the description. You're only getting one different item description per customer number which don't repeat for that customer number. You can see this by adding in: 'order by orders.customer_num, stock.stock_num;' to the end.

I am getting too many solutions when I need only one

I use a query that returns the name of the city with the highest number of orders placed.
This is what I have:
SELECT MAX(o.OrderID) AS [Number of Orders], od.ShipCity
FROM Orders o, [Order Details] od
GROUP BY o.ShipCity
ORDER BY [Number of Orders] DESC
I got all of the cities and their orders instead of just the one city with the most orders.
What happened?
Yeah, there's a couple of things wrong with your query. First, you're getting the max order id , which is presumably some autoincrement column. It's like Karl's answer is first, mine is second, SELECT MAX(answerid) FROM this_discussion = 2.... but that doesn't mean I have more answers than he does.
Rnofx5 is also right... you need to tell your table what to join ON, cause right now it's creating a Cartesian Product. If you're not sure what that is, for now accept that it's a horrible, evil, wicked thing to do and then Google it after we're done fixing the query.
So, we have orders and order details. Presumably orders does not contain City, so we need order details
SELECT count(o.OrderID), od.ShipCity
FROM orders AS o
INNER JOIN [Order Details] AS od
ON o.{a varible that both Orders and Order Details have in common} = .{a varible that both Orders and Order Details have in common}
GROUP BY od.ShipCity
ORDER BY count(o.OrderID) DESC
LIMIT 1;
Okay, so we're joining Orders with Order Details. In order to do that, we need to associate every order with something in Order Details. I don't know your schema, but from the sounds of it probably each order has a corresponding record in Order Details. In that case, you join these two tables using their ID. Something like
ON o.OrderID = od.OrderID
Now, we are counting all of the orders associated with a particular city... and we sorting them by our count, in descending order. And then we are keeping only the very first record that's returned (LIMIT 1)
Depending on your SQL implementation, you may need TOP 1 instead of LIMIT 1. You tagged mysqli, so presumably this is MySQL and in that case you'd want LIMIT not TOP. But be aware that that's a syntax variation you may encounter at some point
You are getting the highest orderID (MAX) per ship city rather then the count.
You instead need COUNT(o.OrderID)
And in MySQL you need to use LIMIT 1 on the end to get only the top most result.

SQL Syntax for Complex Scenario (Deals)

i have a complex query to be written but cannot figure it out
here are my tables
Sales --one row for each sale made in the system
SaleProducts --one row for each line in the invoice (similar to OrderDetails in NW)
Deals --a list of possible deals/offers that a sale may be entitled to
DealProducts --a list of quantities of products that must be purchased in order to get a deal
now im trying to make a query which will tell me for each sale which deals he may get
the relevant fields are:
Sales: SaleID (PK)
SaleProducts: SaleID (FK), ProductID (FK)
Deals: DealID (PK)
DealProducts: DealID(FK), ProductID(FK), Mandatories (int) for required qty
i believe that i should be able to use some sort of cross join or outer join, but it aint working
here is one sample (of about 30 things i tried)
SELECT DealProducts.DealID, DealProducts.ProductID, DealProducts.Mandatories,
viwSaleProductCount.SaleID, viwSaleProductCount.ProductCount
FROM DealProducts
LEFT OUTER JOIN viwSaleProductCount
ON DealProducts.ProductID = viwSaleProductCount.ProductID
GROUP BY DealProducts.DealID, DealProducts.ProductID, DealProducts.Mandatories,
viwSaleProductCount.SaleID, viwSaleProductCount.ProductCount
The problem is that it doesn't show any product deals that are not fulfilled (probably because of the ProductID join). i need that also sales that don't have the requirements show up, then I can filter out any SaleID that exists in this query where AmountBought < Mandatories etc
Thank you for your help
I'm not sure how well I follow your question (where does viwSaleProductCount fit in?) but it sounds like you will want an outer join to a subquery that returns a list of deals along with their associated products. I think it would go something like this:
Select *
From Sales s Inner Join SaleProducts sp on s.SaleID = sp.SaleID
Left Join (
Select *
From Deals d Inner Join DealProducts dp on d.DealID = dp.DealId
) as sub on sp.ProductID = sub.ProductID
You may need to add logic to ensure that deals don't appear twice, and of course replace * with the specific column names you'd need in all cases.
edit: if you don't actually need any information from the sale or deal tables, something like this could be used:
Select sp.SaleID, sp.ProductID, sp.ProductCount, dp.DealID, dp.Mandatories
From SaleProducts sp
Left Join DealProducts as dp on sp.ProductID = dp.ProductID
If you need to do grouping/aggregation on this result you will need to be careful to ensure that deals aren't counted multiple times for a given sale (Count Distinct may be appropriate, depending on your grouping). Because it is a Left Join, you don't need to worry about excluding sales that don't have a match in DealProducts.