SQL Group by for class column - sql

I have two products Green-M and Green-L both share the same productcode 'Clothes' but belong to different classes say Cap and Hat. (They were supposed to be of the same class)
Below are my tables
tbl_Product
ProductName ProductId classic
Green-M 1 2
Green-L 1 3
tbl_size
sizeid sizename
M Medium
L Large
tbl_Class
classid classname
2 cap
3 hat
tbl_ProductCode
Productid Productcode
1 Clothes
I have written the below query to find products that belong to two different classes
select productcode, count(1) from tbl_product p
join tbl_productcode pc on p.productid = pc.productid
group by productcode
having count(1)>1
It gives the below output
Clothes 2
However, it is taking the sizes into consideration.
This is causing an issue because there are products as below
tbl_Product
Product ProductId classid
Yellow - S 1 2
Yellow - M 1 2
Yellow - L 1 2
This will give output
Clothes 3
Which is giving the size count. But I am only looking for products of different classes, irrespective of the number of sizes.

Instead of
COUNT(1)
use
COUNT(DISTINCT ClassId)
That will ignore the different sizes, and just give you the count of how many unique "ClassId" values appear for each ProductId.

Related

SQL Selecting & Counting In the same query

thanks in advance for any help on this, I am a bit of a newbie to MS SQL and I want to do something that I think is achievable but don't have the know how.
I have a simple table called "suppliers" where I can do (SELECT id, name FROM suppliers ORDER BY id ASC)
id
name
1
ACME
2
First Stop Business Supplies
3
All in One Supply Warehouse
4
Farm First Supplies
I have another table called "products"
id
name
supplier_id
1
Item 1
2
2
Item 2
1
3
Item 3
1
4
Item 4
3
5
Item 5
2
I want to list all the suppliers and get the total amount of products for each supplier if that makes sense on the same row? I am just not sure how to pass the suppliers.id through the query to get the count.
I am hoping to get to this:
id
name
total_products
1
ACME
2
2
First Stop Business Supplies
2
3
All in One Supply Warehouse
1
4
Farm First Supplies
0
I really appreciate any help on this.
Three concepts to grasp here. Left Join, group by, and Count().
select s.id, s.name, Count(*) as total_products
from suppliers s
left join products p on s.id=p.supplier_id --the left join gets your no matches
group by s.id, s.name
left join is a join where all of the values from the first table are kept even if there are no matches in the second.
Group by is an aggregation tool where the columns to be aggregated are entered.
Count() is simply a count of transactions for the grouped columns.
Try this :-
SELECT id, name, C.total_products
FROM Suppliers S
OUTER APPLY (
SELECT Count(id) AS total_products
FROM Products P
WHERE P.supplier_id = S.id
) C

Counting and Joining in SQL (oracle)

My database contains 2 tables called products and product_categories.
Product_categories contain category_id and category_name
Products contain category_id and other irrelevant info for this question.
I need to count the number of products using category_id from the products table and also display their name which is in the product_categories table.
Select * FROM product_categories
displays :
category_id, category_name
1 CPU
2 Video Card
3 RAM
4 Mother Board
5 Storage
And
Select * FROM products
displays (condensed):
category_id
399.77 564.89 1
481.56 554.99 1
4058.99 5499.99 2
3619.14 4139 2
2505.04 3254.99 2
... UPTO CATEGORY_ID 5
Current statement :
SELECT category_id , COUNT (1) AS "TOTAL"
FROM products
GROUP BY category_id;
Output:
Category_id, total
1 70
2 50
5 108
4 60
DESIRED RESULT: I need to display the category id followed by category name and finally the total number of products.
Join those tables:
select p.category_id,
c.category_name,
count(*) as total
from products p join product_categories c on c.category_id = p.category_id
group by p.category_id,
c.category_name
You might want to turn it to outer join if you want to display categories that don't exist in the products table.

SQL number of products

I have two tabels :
--Products--
idProduct PK
Category FK
Amount
Name
--Category--
idCategory PK
Category Name
if i have 20 products of different categories for example 3 cars 5 planes 9 types of food
how do i get all of them in a new joined table like this
Category Name (from --Category--) Amount of every product (from --Products--)
Cars 3
Planes 9
And so on , i don't have a table with all the elements from each category so what should i do ?
You may looking for simple join with aggregate function
SELECT CategoryName,COUNT(p.Category ) AS [Amount of every product ]
FROM Category c
INNER JOIN Product p ON c.idCategory = p.Category
GROUP BY CategoryName

SQL: Getting the top 5 child records that together are linked in a link table to the same parent table record

The best way to describe this problem is through an example:
I have 3 tables:
Ingredient:
Id Name
Recipe:
Id Title NumberOfIngredients
RecipeIngredientRelationship:
Id RecipeId IngredientId
This query:
select IngredientId, COUNT(*) cnt
from RecipeIngredientRelationship rel, Recipe r
where rel.RecipeId = r.Id and r.NumberOfIngredients <= 5
group by IngredientId
order by cnt desc
gives me the ingredients in the order of most occurrence for recipes that have 5 or fewer ingredients.
I want to write a query that gives me the top 5 ingredients that together exist in the same recipe. That is if I want to stock my pantry with only 5 ingredients, then these 5 will allow me to cook the most number of recipes.
Please note that the top 5 rows from the above query is not the right answer since the top 5 ingredients are water, sugar, salt, pepper, oil and there are really no recipes with that however salt, potato, chicken, onion, pepper may be the correct answer.
Just to clarify your question:
This will rule out any recipe with more than 5 ingredients since you won't be able to cook a recipe if one ingredient is missing. On the other hand it will include all recipes with less than 5 ingredients.
Furthermore I assume that we could rule out any ingredient that is just used once. Or do you accept a result of a single recipe?
That leads to a variation of all remaining ingredients that needs to be checked against all recipes inclduing the consideration of the recipes with less than 5 ingredients.
Just the simple check with 20 ingredients will lead to 15504 different combinations that needs to be checked against all recipes. To check against 40 ingredients we're talking about more than 650k different combinations....
select top 5 r1id, count(*) from (
select r.RecipeId r1id, r2.RecipeId r2id from RecipeIngredientRelationship r
right join RecipeIngredientRelationship r2
on r2.IngredientId = r.IngredientId
group by r.RecipeId, r2.RecipeId
having count(case when r.IngredientId is null then 1 end) = 0
) t1 group by r1id order by count(*) desc
A 5x cartesian on ingredients could also be a good solution, because it will create the combinations of ingredients taken 5;
then we can group by the different combinations to obtain the number of occurrences:
SELECT I1,I2,I3,I4,I5, COUNT(*) total
FROM (
SELECT
r1.RecipeId,
r1.IngredientId I1,r2.IngredientId I2,r3.IngredientId I3,r4.IngredientId I4,r5.IngredientId I5
FROM RecipeIngredientRelationship r1
JOIN RecipeIngredientRelationship r2 ON (r1.RecipeId=r2.RecipeId and r1.IngredientId<r2.IngredientId)
JOIN RecipeIngredientRelationship r3 ON (r3.RecipeId=r2.RecipeId and r2.IngredientId<r3.IngredientId)
JOIN RecipeIngredientRelationship r4 ON (r4.RecipeId=r2.RecipeId and r3.IngredientId<r4.IngredientId)
JOIN RecipeIngredientRelationship r5 ON (r5.RecipeId=r2.RecipeId and r4.IngredientId<r5.IngredientId)
) x
GROUP BY I1,I2,I3,I4,I5
ORDER BY total desc

Query to consolidate multiple columns into 1

we have a database query that queries for all products on our website.
It currently has 10,000 products and some of these products reside in 3 categories of products which the category information is stored in a tracking table.
This then means our queries return 3 instances of those products.
What Im wondering is. is it possible to query a database and return a single instance of these products but place the category names into a single column like a list ?
Is this known as an aggregate function? or is this some sort of sub query that will consolidate the information into 1 column for use.
We are using MSSQL 2012
table products
id
product_name
display_name
table tracking
id
product_id
category_id
view_order
table categories
category_id
category_name
red tshirt with an id 1
categories
Mens Wear with id of 1
Tshirts with id of 2
clothing with id of 3
what we would like as the output is
Product_name category
Red Tshirt Mens Wear,Tshirts,Clothing
instead of
Product_name category
Red Tshirt Mens Wear
Red Tshirt Tshirts
Red Tshirt clothing
which is what we are getting now
The following TSQL using the For XML trick to create a CSV field will do the trick
with combined (product_name, category) as (
select product_name, category_name
from
products
inner join tracking on products.id = tracking.product_id
inner join categories on categories.id = tracking.category_id
)
select
product_name,
stuff((select distinct ',' + nullif(category,'')
from combined t2 where t2.product_name = t1.product_name
for XML PATH(''),TYPE).value('.','VARCHAR(MAX)'),1,1,'') as category
from combined t1