Query check all parents are present - mysql

I have two tables :
Item_category:
id
item_id
category_id
1
4
1
2
5
2
3
5
3
And category:
id
parent_id
1
null
2
1
3
2
All items have a category, and in table item_category I should also have rows with parent category. I try to make a query that show me all items where a parent category is missing. In this exemple item_id : 5 - category : 1 is missing, the query in SQL should show this row.
Any ideas?
Thx a lot for your help. Kinda stuck

You can try something like this
SELECT items.* FROM items LEFT JOIN item_category ON item_id = items.id LEFT JOIN category ON category_id = category.id WHERE parent_id IS NULL

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);

Inner join within table

I have a table categories with the following fields:
id, content, is_subcategory, topic_id
Here comes an examplatory set of data:
id content is_subcategory reference_id
=============================================
1 Games 0 989898989
2 Xbox 1 1
3 Playstation 1 1
4 Furniture 0 121212121
5 Sofa 1 4
6 Closet 1 4
7 Music 0 989898989
8 Pop 1 7
9 Reggae 1 7
Explanation:
If the category is a subcategory, its reference_id is the id of the parent category. For example, Sofa has 4 as its reference_id as 4 is the id of Furniture.
If the category is a parent category, its reference_id is the id of another table topics. For example, Music is a parent category and has 989898989 as its reference_id which is the id for the topic "entertainment".
How do I achieve that I can select only those subcategories whose parent category has 989898989 as its reference_id?
You can do just like it was 2 different tables:
select * from categories c, categories parent
where c.reference_id=parent.id and parent.reference_id=989898989 and c.is_subcategory = 1
SELECT * FROM category sub, category super WHERE
sub.reference_id = super.id AND super.reference_id = 989898989
AND sub.is_subcategory = 1
Since you alredy figured out that you need a self join for this question I am sure you can understand my solution. If not, just let me know.
Give different aliases and try
SELECT id,content FROM `categories` Child INNER JOIN
`categories` Parent ON Child.`reference_id` = Parent.`id`
WHERE Parent.reference_id=989898989 and Child.is_subcategory = 1
I like to suggest inner join for better perfomance.

Apply filter on joined tables with MySQL

I store some data in MySQL and want to filter out rows that match a given criteria.
Sounds easy, but it is not since there are some join criteria involved.
I do have the following tables:
items : id, ...
genres: id, name:varchar, item_id
Each item has multiple genres.
The query should filter out items if at least one genre does match a given genre name (or a set of names).
For example:
Item with id 1 has 3 genres
- genre name = 'foo'
- genre name = 'bar'
- genre name = 'baz'
Item 1 may not be part of the result set if the given genre name is 'bar', ['bar', 'baz', 'xyz'], etc.
I tried to left join the genres on the items and applied a WHERE statement with "genres.name NOT IN (?)". ? is the given set of genre names.
This (of course) only works for items with exactly one genre. The same could be achieved by multiple WHERE conditions: WHERE name <> 'a' AND name <> 'b' ...
Any ideas how to get this query done properly?
Thanks in advance!
You can do something like this (see sqlfiddle):
select i.name as item, g.name as genre
from items as i
left join genres as g
on i.id = g.item_id
where i.id not in
(select distinct g2.item_id from genres as g2
where FIND_IN_SET(g2.name,'foo,bar'));
And this way it works if you want to check against multiple genre names.
You can use a correlated subquery.
Example:
SELECT id
FROM items i
WHERE NOT EXISTS (SELECT 1
FROM genres g
WHERE g.`name` = 'bar'
AND i.id = g.item_id);
A correlated subquery differs from other subqueries in that it references the outer query.
Correlated subqueries are run for each row projected/selected by the outer query.
Well hopefully I understand what you are asking for and I think MySQL and T-SQL will be similar in this respect. These are the sample tables I assumed you were using from your example.
Table1
ID NAME
1 Item 1
2 Item 2
3 Item 3
4 Item 4
5 Item 5
6 Item 6
Table2
ID NAME ITEM_ID
1 Genre 1 1
2 Genre 2 1
3 Genre 3 1
4 Genre 1 2
5 Genre 2 2
6 Genre 3 2
7 Genre 1 3
8 Genre 2 3
9 Genre 3 3
10 Genre 1 4
Here is the SQL to filter out items if they match one of your criteria.
SELECT *
FROM table1 a, table2 b
WHERE a.id = b.item_id
AND b.name NOT IN ('Genre 1', 'Genre 2')
Results returned from above query on sample tables.
ID NAME ID_1 NAME_1 ITEM_ID
1 Item 1 3 Genre 3 1
2 Item 2 6 Genre 3 2
3 Item 3 9 Genre 3 3
You could also filter out against the genre_id (table2.id) instead. If you plan to use a sub-query instead of hard coded values then you should switch the "NOT IN" to a "NOT EXISTS" and re-write the "AND" portion accordingly as "NOT IN" does not like null values.
This query also assumes that each "Item" has at least 1 "Genre." I am sure you can play with it if you want all "Items" excluding the ones that match your criteria.
select * from items i where not exists
(select '' from genres gen where gen.item_id = i.id and gen.name in ('foo','pop') )
A shorter ans simpler query.
The inner query checks genre name in the keywords list , if the no row is returned then the current row of outer query is selected.
Verify the output
at here.
Thanks to Kyra
,i borrowed his schema from sql fiddle.

Select rows that match multiple rows in related table

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