Select rows that match multiple rows in related table - mysql

I have three tables:
item
id name etc
--------------------
1 Rex
2 Fido
3 Geoff
category
id name
------------
1 Dogs
2 Humans
3 Mammals
category_item
category_id item_id
--------------------
1 1
3 1
1 2
3 2
2 3
3 3
I also have an array of category ids. I would like to count the number of items that are related to ALL of the categories in the array.
For example...
Category_ids Result
----------------------
1,2 0
2,3 1
1,2,3 0
Pretty sure I'm gonna kick myself when I figure this one out.

Please try query given below..
select count(*) AS Result from (
SELECT count(item_id) FROM category_item
WHERE
category_id in (2 ,3)
GROUP by item_id
HAVING count(*) = 2
) AS temp
In this query put count(*) value equal to total number of category_id for example if you are checking for category_ids 1,2,3 then put having count(*) = 3. In this query let assume you provide category_id 1 and 2 then it will fetch total number of existence of item_id with
I hope this query will helpful for you.
thanks

Related

Get either the value or null entry on row in SQL

I have four tables, products, priceplans, and two category tables as follows:
products
---------
product_id
a
b
priceplans
---------
priceplan_id
a
b
product_id (can be null)
price
categoryA
---------
a (id)
category_name
categoryB
---------
b (id)
category_name
In the priceplans a and b are category ids in other tables, the combination (a,b,product_id) is unique but product_id can also be null, and the priceplan should then use the general priceplan for the (a,b,null) combination. That is the theory, but it is not working out as well as I had hoped and I havent managed to construct a query to only filter them out.
Example:
products - 3 products, 2 in the same category, one in another category
product_id a b
1 1 1
2 1 1
3 1 2
priceplans - 3 plans,
1 is for the default (a,b)=(1,1) category combination when there is no product_id,
2 is supposed to override the default as we have declared a product_id, and
3 is the default for (a,b)=(1,2) combination
priceplan_id a b product_id price
1 1 1 null 10
2 1 1 2 15
3 1 2 null 12
What I want the outcome to look like when I join products with the priceplans is:
product_id a b priceplan_id price
1 1 1 1 10
2 1 1 2 15
3 1 2 3 12
If for the product with a category combination (a,b)=(1,1) and id=1 i want the priceplan with combination (a,b,1) if it exists, if not i want the (a,b,null) priceplan. Any suggestions?
I finally managed to create the query I was looking for:
select pro.*, pp.* from products pro
left join price_plans pp
on pro.a=pp.a
and pro.b=pp.b
and (pro.product_id=pp.product_id or pp.product_id is null)
left join price_plans pp2
on pro.a=pp2.a
and pro.b=pp2.b
and pp2.product_id =pro.product_id
where pp.product_id <=> pp2.product_id

MySQL Get Parent With Child Rows Together

i have searched for questions like this and although many are similars, are not answering exact my questions and queries not work.
Assuming we have the following table
id category_name parent_id
------------------------------------
1 test 0
2 test1 0
3 new_cat 1
4 new_catx 2
5 cat5 1
I want an sql query where the output will be like this
id category_name parent_id
------------------------------------
1 test 0
3 new_cat 1
5 cat5 1
2 test1 0
4 new_catx 2
In sort the output query is sorted based on parent_id. The parent_id = 0 is the root category, then child are following, and then again another parent with it's child. etc
This will work for a 1-level tree, i.e. for a tree containing only parents and their children:
SELECT *
FROM mytable
ORDER BY CONCAT(IF(parent_id=0, '', parent_id), id)
Demo here
Ideally you should use a mapping table for this, to make your solution cleanly scalable. Change your original table struct to
id category_name
---------------------
1 test
2 test1
3 new_cat
4 new_catx
5 cat5
...and have a parent mapping table, like so:
id parent_id
---------------------
3 1
4 2
5 1
Then you would simply modify Giorgos Betsos' excellent query to read:
select t.id, t.category_name, p.parent_id
from testtable t left outer join parents p
on t.id = p.id
ORDER BY CONCAT(IF(p.parent_id is null, '', p.parent_id), t.id);

MYSQL: Select entries in relation to multiple rows of multiple table

I have three tables that I can't change the structure of:
facet
id name
-----------------
1 Series
2 Material
value
id facet_id name
----------------------------------
1 2 Glass
2 2 Metal
3 1 Series #1
4 1 Series #2
5 1 Series #3
product_facet_values
product_id value_id
-----------------------------------
1 1
1 3
2 1
2 4
3 2
3 5
4 1
I am trying to write two queries:
/1. One that will return the ids that represent the series facet from the values table where a product record is Glass and has any series. So an output like this:
id facet_id name
----------------------------------
3 1 Series #1
4 1 Series #2
Record 1 is not a series.
Record 2 is not a series.
Record 3 is returned because product #1 has both a series and material and the material is glass.
Record 4 is returned because product #2 has both a series and material and the material is glass.
Record 5 is not returned because product #3 has the material of metal even though it has both a series and material.
/2. Same as number one but return a list of product ids.
product_id
---------------
1
2
Product #1 is returned because it has both a series and material and the material is glass.
Product #2 is returned because it has both a series and material and the material is glass.
Product #3 is not returned because it has the material of metal even though it has both a series and material set.
Product #4 is not returned because it has no series set even though the material is glass.
FIRST QUERY:
try this.. I believe this will do the trick.
SELECT
v.id
FROM value v
JOIN product_facet_values pfv ON pfv.value_id = v.id
WHERE pfv.product_id IN
( SELECT
product_id
FROM product_facet_values
WHERE
product_id IN
( SELECT
product_id
FROM product_facet_values
GROUP BY product_id
HAVING COUNT(*) > 1
)
AND value_id = 1
)
AND v.facet_id = 1;
SECOND QUERY:
the inner part of the same query returns the products that have a value of 1 and a value of something other than one so it would be this
SELECT
product_id
FROM product_facet_values
WHERE
product_id IN
( SELECT
product_id
FROM product_facet_values
GROUP BY product_id
HAVING COUNT(*) > 1
)
AND value_id = 1
EXPLANATION:
INNERMOST SUBQUERY:
SELECT
product_id
FROM product_facet_values
GROUP BY product_id
HAVING COUNT(*) > 1
give me products that have more than one record per product (later to be filtered by 'Glass' and 'Series')
MIDDLE SUBQUERY:
SELECT
product_id
FROM product_facet_values
WHERE
product_id IN
(
INNERMOST SUBQUERY
)
AND value_id = 1
give me products that have the value_id = 1 (aka 'Glass') that have more than one record.
OUTERMOST QUERY:
SELECT
v.id
FROM value v
JOIN product_facet_values pfv ON pfv.value_id = v.id
WHERE pfv.product_id IN
(
MIDDLE SUBQUERY
)
AND v.facet_id = 1;
give me the value id for the products that are related to 'Glass' but whos facet_id = 1 (aka series)

Count duplicate values in sql server with primary key coloumn

id(PRIMARY KEY) item
--- -------
1 book
2 pen
3 computer
4 book
5 pen
6 mobile
7 book
This is main table. i want result(item count is >1) as
ID ITEM COUNT
---- ------- -------
1 BOOK 3
4 BOOK 3
7 BOOK 3
2 PEN 2
5 PEN 2
I am writing query as:
SELECT ID,ITEM,COUNT(ITEM)
FROM MAIN
GROUP by ID,ITEM
HAVING COUNT(ITEM)>1
ORDER BY ITEM
and getting result as:
ID ITEM COUNT
---- ------- -------
SELECT m.ID, m.ITEM, m1.`COUNT`
FROM MAIN m
JOIN (
SELECT ITEM, COUNT(*) AS `COUNT`
FROM MAIN
GROUP BY ITEM
HAVING `COUNT` > 1
) m1
ON m.ITEM = m1.ITEM
ORDER BY m.ITEM, ID
Your problem was that you had both ID and ITEM in the GROUP BY. Since IDs are unique, you never had any duplicates.
The subquery is used to get the count for each item. Then you join it with the original table so you can show each ID separately.

Group by - Overriding default behaviour of deciding row under each group in result

Extending further from this question Query to find top rated article in each category -
Consider the same table -
id | category_id | rating
---+-------------+-------
1 | 1 | 10
2 | 1 | 8
3 | 2 | 7
4 | 3 | 5
5 | 3 | 2
6 | 3 | 6
There is a table articles, with fields id, rating (an integer from 1-10), and category_id (an integer representing to which category it belongs). And if I have the same goal to get the top rated articles in each query (this should be the result):-
Desired Result
id | category_id | rating
---+-------------+-------
1 | 1 | 10
3 | 2 | 7
6 | 3 | 6
Extension of original question
But, running the following query -
SELECT id, category_id, max( rating ) AS max_rating
FROM `articles`
GROUP BY category_id
results into the following where everything, except the id field, is as desired. I know how to do this with a subquery - as answered in the same question - Using subquery.
id category_id max_rating
1 1 10
3 2 7
4 3 6
In generic terms
Excluding the grouped column (category_id) and the evaluated columns (columns returning results of aggregate function like SUM(), MAX() etc. - in this case max_rating), the values returned in the other fields are simply the first row under every grouped result set (grouped by category_id in this case). E.g. the record with id =1 is the first one in the table under category_id 1 (id 1 and 2 under category_id 1) so it is returned.
I am just wondering is it not possible to somehow overcome this default behavior to return rows based on conditions? If mysql can perform calculation for every grouped result set (does MAX() counting etc) then why can't it return the row corresponding to the maximum rating. Is it not possible to do this in a single query without a subquery? This looks to me like a frequent requirement.
Update
I could not figure out what I want from Naktibalda's solution too. And just to mention again, I know how to do this using a subquery, as again answered by OMG Ponies.
Use:
SELECT x.id,
x.category_id,
x.rating
FROM YOUR_TABLE x
JOIN (SELECT t.category_id,
MAX(t.rating) AS max_rating
FROM YOUR_TABLE t
GROUP BY t.category_id) y ON y.category_id = x.category_id
AND y.max_rating = x.rating