Sql categories products count query - mysql

Hi I have a difficulty with one query if someone can help would be great
What I m trying to do is to get all counts by selected category. For example If I haven't selected any category the result is going to be like this:
Category-70 ( 2 ) <- Product-57, Product-56
Category-64 ( 2 ) <- Product-57, Product-50
Category-61 ( 1 ) <- Product-56
Category-73 ( 1 ) <- Product-50
So that's easy. I have a query like this one:
http://sqlfiddle.com/#!9/4f188/1
So I would like to pass category ids to my query, and get counts based on this ids, something like this if, I pass category id 70 the result has to be
Category-70 ( 2 ) <- Product-57, Product-56
Category-64 ( 1 ) <- Product-57, [Product-50 is gone because is not in cateogry id 70]
Category-61 ( 0 )
Category-73 ( 0 )
If I pass category id 70 and 64 the result must be
Category-70 ( 1 ) <- Product-57, [Product-56 is gone because is not in category 70 and 64]
Category-64 ( 1 ) <- Product-57
Category-61 ( 0 ) [Product-56 is gone, because is not in category 70 and 64 ]
Category-73 ( 0 ) [Product-50 is gone because is not in category 70 and 64]
or if I give as parameter category id 73 the result must be
Category-70 ( 0 ) [products are not counted because they are not in 73]
Category-64 ( 1 ) <- Product-50
Category-61 ( 0 ) [products are not counted because they are not in 73]
Category-73 ( 1 ) <- Product-50
Is that even possible :), ty for any help...

+1 for the SQL fiddle example, very useful.
I believe this should fix your problem (added a sub select to your join)
SELECT Concat('Category-',c.category_id),
count(DISTINCT p2c.product_id) as products
FROM category c
LEFT JOIN product_to_category p2c
ON (c.category_id = p2c.category_id AND p2c.product_id) AND p2c.product_id in
(select product_id from product_to_category where category_id = #input)
LEFT JOIN category_path cp ON (cp.category_id = c.category_id AND cp.path_id = c.category_id)
WHERE
cp.level <= 2
GROUP BY c.category_id
ORDER BY c.sort_order

Related

Sum Value as per case in MySql

As per below MySql Query fetch product count correctly see the red box in image. I need if icat_id 444 than 448 count (158) SUM in category_count (435) of icat_id 444.
After this icat_id 444 total sum of 435 + 158 = 593.
But Case not working properly. Please help
SELECT c.vcategory, c.icat_id,
COUNT( DISTINCT product_cat_rel_1.iprod_id) AS category_count,
UPPER(REGEXP_REPLACE(CONCAT(' ', c.vcategory), ' (.)[^ ]+', '\\1' )) AS category_name,
SUM(CASE WHEN (c.icat_id = '444') THEN 1 WHEN (c.icat_id = '448') THEN 1 ELSE 0 END) AS tt
FROM product
INNER JOIN product_cat_rel_1 ON product_cat_rel_1.iprod_id = product.iprod_id
INNER JOIN product_price ON product_price.iprod_id = product.iprod_id
INNER JOIN category as c ON c.icat_id = product_cat_rel_1.icat_id
WHERE product.estatus='1'
AND product_cat_rel_1.icat_id in (444,448,450,454,471,549,592,741,765,782)
GROUP BY product_cat_rel_1.icat_id
As per requirement group by both 444 and 448 as 444 and sum up corresponding value. Apply changes in given query.
-- MySQL
SELECT c.vcategory,
CASE WHEN product_cat_rel_1.icat_id IN (444, 448)
THEN 444
ELSE product_cat_rel_1.icat_id
END icat_id,
COUNT( DISTINCT product_cat_rel_1.iprod_id) AS category_count,
UPPER(REGEXP_REPLACE(CONCAT(' ', c.vcategory), ' (.)[^ ]+', '\\1' )) AS category_name,
SUM(category_count) AS tt
FROM product
INNER JOIN product_cat_rel_1 ON product_cat_rel_1.iprod_id = product.iprod_id
INNER JOIN product_price ON product_price.iprod_id = product.iprod_id
INNER JOIN category as c ON c.icat_id = product_cat_rel_1.icat_id
WHERE product.estatus='1'
AND product_cat_rel_1.icat_id in (444,448,450,454,471,549,592,741,765,782)
GROUP BY CASE WHEN product_cat_rel_1.icat_id IN (444, 448)
THEN 444
ELSE product_cat_rel_1.icat_id
END

mysql search keywords in string table

I have a catID column in product table, it is contain category ids as string,
Something like that '142,156,146,143'
and i Have a query '?catID=156,141,120'
i want to search each id in catID column.
I use this query:
SELECT * FROM product WHERE catID REGEXP '156|141|120'
this code return products which have any id in catID column , but I want to return products which is have all id,
So , I'am looking for and operator in REGEXP , but I'am couldn't find.
I want to use REGEXP or something like that which function provide to find product with one query , I don't wan to use
catID LIKE '156' AND catID LIKE '141' ....
if it is posibble.
EDIT : I don't want to perform a function one more time , because the query can be have 100+ id so it's make more harder to write code,
You need to use find_in_set() for each category id parameter in order to find the values in set,also if you can alter the schema then do normalize it, by having another junction table which holds the relation from this table to category table
select * from
product
where
find_in_set('142',catID ) > 0
For multiple values like find_in_set('161,168,234,678',preferred_location ) > 0 no it can't be possible doing like this you have to perform for each location id like
select * from
product
where
find_in_set('142',catID ) > 0
and find_in_set('156',catID ) > 0
and find_in_set('146',catID ) > 0
and find_in_set('143',catID ) > 0 ... for more
Database normalization
find_in_set
Sample Schema
Table
Products (id,other columns)
Categories (id,other columns)
Product_categories (id,product_id,category_id)
Product_categories is a junction table which will hold product_id and one category_id per each product so each will have a relation with single category and single product at a time
For example
Products
id name
1 product 1
2 product 2
Categories
id name
142 category 1
156 category 2
146 category 3
143 category 4
Product_categories
id product_id category_id
1 1 142
2 1 156
3 1 146
4 1 143
Now you can join these tables and query like below using in() and count should be equal to the no of category ids provided as parameter
select p.* from
Products p
join Product_categories pc on (p.id = pc.product_id)
where pc.category_id in(142,156,146,143)
group by p.id
having count(distinct pc.category_id) = 4
Sample Demo
or if you can't count the provided category ids as parameter you can do this by following query
select p.* from
Products p
join Product_categories pc on (p.id = pc.product_id)
where pc.category_id in(142,156,146,143)
group by p.id
having count(distinct pc.category_id) =
ROUND (
(
LENGTH('142,156,146,143')
- LENGTH( REPLACE ( '142,156,146,143', ",", "") )
) / LENGTH(",")
) + 1
Sample Demo 2

SQL query problems transpose MySQL

There are 2 simple tables
People:
person_id
Name
Reading assestment
date
person_id
quality
speed
Trying to create sql query
SELECT
AVG(r.quality),
AVG(r.speed),
FROM reading_assestment r,people p
where r.person_id =p.person_id
and person_id="3"
Current output:
Quality Speed
77 65
Outcome I am looking for:
Assestment Value
Quality 77
Speed 65
It is something to do with transpose , pivots.
The most general way is to start with your query and then unpivot using separate logic:
select (case when n = 1 then 'Quality' else 'Speed' end) as Assessment,
(case when n = 1 then avg_quality else avg_speed end) as Value
from (select AVG(r.quality) as avg_quality, AVG(r.speed) as avg_speed
from reading_assestment r join
people p
on r.person_id =p.person_id
where person_id = 3
) t cross join
(select 1 as n union all select 2) n
SELECT
AggResults.person_id AS person_id,
Assesment.Name AS AssessmentName,
CASE WHEN Assessment.Name = 'Quality' THEN AggResults.AvgQuality
WHEN Assessment.Name = 'Speed' THEN AggResults.AvgSpeed
ELSE NULL
END AS AssessmentValue
FROM
(
SELECT
people.person_id AS person_id,
AVG(quality) AS AvgQuality,
AVG(speed) AS AvgSpeed
FROM
reading_assessment
INNER JOIN
people
ON reading_assessment.person_id = people.person_id
GROUP BY
people.person_id
)
AS AggResults
CROSS JOIN
(
SELECT 'Quality' AS Name
UNION ALL
SELECT 'Speed' AS Name
)
AS Assessment
WHERE
AggResults.person_id = 3
I moved the = 3 to the outer query, just for ease of use. Most optimisers will treat both options similarly.

Mysql query issue with multiple table table join

Hi this is my tables
table 1 => products
id product price active
3 sample 1500 1
4 sample2 2300 2
table 2 => product_attibute_value
id product option_value
1 3 Green
2 3 Red
and table 3 => product_attribute_options
id product option_value
1 2 8
2 2 7
and my query is
SELECT typ.*
FROM products typ , attibute_value tyav
WHERE typ.active='1' AND ( tyav.option_value = 'Green' ) AND typ.id=tyav.product
GROUP BY typ.id
ORDER BY typ.price ASC
This working fine. Now I want to add product_attribute_options table also.
Now I added new query like this
SELECT typ.*
FROM products typ , attibute_value tyav, product_attibute_options tyop
WHERE typ.active='1' AND ( tyav.option_value = '7' OR tyav.option_value = 'Orange' ) OR
( tyav.option_value = '7' OR tyav.option_value = 'Orange' ) AND
typ.id=tyav.product OR typ.id=tyop.product
GROUP BY typ.id
ORDER BY typ.price ASC
I am showing option value in one page, and if i selected this option like 8 or or orange, it will show the product. this product should come from both attribute_options table and attribute_value table.
Its not coming exactly. What I did mistake in this query? Thanks in advance
Try this:
SELECT p.*
FROM products p
INNER JOIN product_attibute_value pav ON p.id = pav.product
INNER JOIN product_attibute_options pao ON p.id = pao.product
WHERE p.active = 1 AND ( pav.option_value = '7' OR pao.option_value = '7' )
GROUP BY p.id
ORDER BY p.price ASC
It is better if you use JOIN sentences and conditions on each of them.
Try this:
SELECT typ.*
FROM products typ
JOIN attibute_value tyav ON typ.id=tyav.product
JOIN product_attibute_options tyop ON typ.id=tyop.product
WHERE typ.active='1'
AND ( tyav.option_value = '7' OR tyav.option_value = 'Orange' )
GROUP BY typ.id
ORDER BY typ.price asc

How to select grouped records only if every record in a group meets a certain criteria in MySQL?

I'm using MySQL 5.0.88/Coldfusion8 and I have a table that contains products based on barcodes/EANs.
So a product 123 in size S,M,L,XL will have four records in the table
product size ean qty disregard_inventory
123 S 1111111111111 5 0
123 M 1111111111112 7 0
123 L 1111111111113 1 0
123 XL 1111111111114 2 0
Right now I'm searching this table like so:
SELECT count(a.id) AS total_records, a.disregard_inventory, a.qty
FROM artikelstammdaten a
...
GROUP BY a.style
HAVING sum(a.qty) != 0 OR (a.disregard_inventory = 1)
This works ok and selects all products which are not sold out (sum > 0 across all eans)/always available
I now want to add a function, so users can search for products that have at least 1pc in each size. In this case, style 123
123 S 1
123 M 0
123 L 12
123 XL 9
would not be included in the resultset as size M is sold out.
However I can't get it to work. This is what I have (produces rubbish):
GROUP BY a.style
<cfif form.select_type EQ "running_sizes">
HAVING a.qty!= 0 OR ( a.disregard_inventory = 1 )
<cfelse>
HAVING sum(a.bestand) != 0 OR (a.disregard_inventory = 1)
</cfif>
Question:
Is it at all possible to group by style and only include style when each underlying ean has a quantity > 0? If so, thanks for pointers!
EDIT:
here is my full query, which I'm testing with:
SELECT count(a.id) AS gesamt_datensaetze, a.nos, a.nos_anzeige, a.bestand, SUM(a.bestand>0) AS what
FROM artikelstammdaten a
WHERE a.aktiv = "ja"
AND a.firma LIKE "some_company"
// groups by seller_id, style
GROUP BY a.iln, a.artikelnummer
HAVING sum(a.bestand) != 0 OR (a.nos = "ja" AND a.nos_anzeige = "ja")
AND ( SUM(a.bestand > 0) = COUNT(*))
Solution:
Partenthesis mising:
HAVING (( sum(a.bestand) != 0 ) OR (a.nos = "ja" AND a.nos_anzeige = "ja" ))
AND ( SUM(a.bestand > 0) = gesamt_datensaetze )
This works.
I suggest the following query:
SELECT COUNT(a.id) AS total_records, a.disregard_inventory, a.qty
FROM artikelstammdaten a
...
GROUP BY a.style
HAVING (SUM(a.qty) != 0 OR (a.disregard_inventory = 1))
AND (SUM(qty>0) = total_records)
The last condition I added to the query enables to return a style only if the number of sizes for this product (total_records) is equal to the number of available sizes for this product (SUM(qty>0)).
qty>0 will either return 0 (when the product is not available in the given size, or 1 (when it is available). So SUM(qty>0) will return an integer number between 0 and the total number of sizes.
You can accomplish this using a join on a subquery. Basically, join on the set of product IDs where the quantity available is zero, and then only return results where there was no match.
SELECT count(a.id) AS total_records, a.disregard_inventory, a.qty
FROM artikelstammdaten a
LEFT JOIN (
SELECT DISTINCT id
FROM artikelstammdaten
WHERE qty = 0
) b
ON b.id = a.id
WHERE b.id IS NULL
...
GROUP BY a.style
HAVING sum(a.qty) != 0 OR (a.disregard_inventory = 1)
I think you should check MIN(a.qty):
select product from t group by product having min(qty)>0