SELECT with different values for foreign key - mysql

I have 2 tables:
Products(..., category_id)
Categories(id, name, level_1_parent_id, level_2_parent_id)
category_id is foreign key for Categories(id)
If it's first level category level_1_parent_id is NULL,
If second level category level_2_parent_id is NULL, level_1_parent_id is set,
if third level both are set.
I'm selecting products like this
SELECT *
FROM Products
WHERE category_id = ${category_id}
What I need to achieve:
Select products from child categories if its first or second level category.
So for example if I'm selecting from category with id == 1 (which is first level id) I want to select products with category_id equals 1 and other categories with level_1_parent_id == 1 and the same for second level category.
Is that possible somehow?

we can use nested query here.
SELECT * FROM Products WHERE category_id = ${category_id} or
category_id in (select distinct id from Categories where level_1_parent_id = ${category_id} or level_2_parent_id = ${category_id})

You get the category list by joining the table to itself first, then get the products associated with each of the categories found. Note the use of alias's for each of the tables in the from and join clauses.
SELECT *
FROM Categories c1
LEFT JOIN Categories c2
ON c2.level_1_parent_id = c1.id
LEFT JOIN Categories c3
ON c3.level_1_parent_id = c1.id AND c3.level_2_parent_id = c2.id
JOIN Products p
ON p.category_id = c1.id OR p.category_id = c2.id OR p.category_id = c3.id
WHERE c1.category_id = ${category_id}

Related

Get all values from intermediate table

I have a mySQL three-table many-to-many setup with link table, simplified here:
categories
category_id
category_name
categories2entries
category_id,
entry_id
entries
entry_id
entry_text
I need to return all entries for a given category name but I want to include a list of all the categories a given entry is attached to. For example, if a search is for Addictions and the entry is also listed in categories Mental health and Young people, I want an output field for each result with all three categories listed.
How do I do this?
You need direct lookup for to get the list of entries, and backward lookup for to get categories list for each entry. Backward lookup must use another tables copies.
SELECT e.entry_text,
GROUP_CONCAT(c2.category_name) belongs_to
FROM categories c1
JOIN categories2entries ce1 ON c1.category_id = ce1.category_id
JOIN entries e ON ce1.entry_id = e.entry_id
JOIN categories2entries ce2 ON ce2.entry_id = e.entry_id
JOIN categories c2 ON c2.category_id = ce2.category_id
WHERE c1.category_name = 'Category Name'
GROUP BY e.entry_text
If you need the same for more than one category (maybe even all) then
SELECT c1.category_name,
e.entry_text,
GROUP_CONCAT(c2.category_name) belongs_to
FROM categories c1
JOIN categories2entries ce1 ON c1.category_id = ce1.category_id
JOIN entries e ON ce1.entry_id = e.entry_id
JOIN categories2entries ce2 ON ce2.entry_id = e.entry_id
JOIN categories c2 ON c2.category_id = ce2.category_id
/* WHERE c1.category_name IN ({Category Names list}) */
GROUP BY c1.category_name,
e.entry_text

SQL query for a selection from a table with categories and subcategories

Structure of the Category table:
id
title
parent_id
Structure of the Item table:
id
title
is_active (0 или 1)
category_id
table structure
Tables are associated with the category_id field by a one-to-many relationship. Those. 1 category can have many items.
The two-level hierarchy in the Category table. This defines the main categories and subcategories. Categories are those records in which parent_id = NULL. And subcategories, these are those records in which parent_id = to some id.
One Item can belong to both the main category (where parent_id = null) and the subcategory (child). Item can be active and not active (0 or 1).
You need to make a query and select from the Category table all the main categories (which have parent_id = null) that have active items (is_active = 1) and which have subcategories also with active itemes.
i.e If the child subcategory has items with is_active = 0, then do not display this category.
I could only choose the main categories in which only active items:
SELECT categories.title, count(analyses.id) FROM items
INNER JOIN categories on items.category_id = categories.id
WHERE categories.parent_id IS NULL
AND categories.is_active = 1
GROUP BY analyses.category_id
ORDER BY analyses_categories.title
But with subcategories can not cope anymore, tell me please who has more experience.
It's a little unclear what you are trying to count (just the active items associated with the parent?), but I would use exists to find out which have children with active items as well:
select c.title, count(*)
from categories c
join item i on i.category_id = c.id
where c.parent_id is null and i.is_active = 1 and exists (
select 1
from categories c2
join item i on c2.id = i.category_id
where c2.parent_id = c.id and i.is_active = 1
)
group by c.title

Where clause on a string rather than id

I need to get all articles out of my database if they fall under a category or sub category.
articles:
id | title | content | category_id (fk)
categories
id | title | parent_id
1 toys 1
2 trains 1
3 pets 3
I perform:
SELECT * FROM categories LEFT JOIN articles ON categories.id = articles.category_id WHERE categories.id = ? OR WHERE categories.parent_id = ?
The above works, but now I want to use the category title instead of an id. So something like:
SELECT * FROM categories LEFT JOIN articles ON categories.id = articles.category_id WHERE **categories.title** = ? OR WHERE ??? not sure how to handle this bit
But im not sure how to handle the OR WHERE, as I don't know the categories id value.
Is there a way to do this without performing a category id lookup query first?
You could, first, get a list of categories that are child categories of a parent category and the parent category, then, join to find the matching articles.
SELECT * FROM(
SELECT *
FROM categories
WHERE title = 'toys'
UNION
select a.*
FROM categories a
JOIN categories b ON (a.parent_id = b.id)
WHERE b.title = 'toys'
) c
JOIN articles ON (c.id = articles.category_id);
SELECT * FROM categories c
LEFT JOIN articles ON c.id = articles.category_id
WHERE **c.title** = ? OR
c.title IN (select title from categories ca where c.title = ? AND ca.id = c.parent_id)
You can control if title of row's parent match whether or not matches with special title. There might be more efficient ways but this design is very similar to yours.

Pull data from 3 tables

I have 3 tables as follows :
Table 1: Product
id_product [Primary Key],added_time.
Table 2: Category
id_category [Primary Key],Category_name.
Table 3: product_category
id_category,id_product [Both Foreign Keys]
I want to pull Data as
Category_name,No Of Products in this Category,Last time when product was added to Category(Latest product added_time).
You could use this SQL:
SELECT Category.Category_name,
Count(DISTINCT Product.id_product) AS num_products,
Max(Product.added_time) last_added_time
FROM Category
LEFT JOIN product_category
ON product_category.id_category = Category.id_category
LEFT JOIN Product
ON Product.id_product = product_category.id_product
GROUP BY Category.Category_name;
Note that by using LEFT JOIN you will be certain to list all categories even those for which no products exist. If you don't want those, replace both LEFT keywords with INNER.
Note also that in standard SQL you need to GROUP BY any columns you mention in the SELECT list, unless they are aggregated, like with MAX or COUNT.
SELECT C.`Category_name`,
(SUM(IF(P.`id_product`IS NULL,0,1))) AS No_of_Products,
MAX(P.`added_time`) AS Latest_time
FROM
Category C
LEFT JOIN
product_category P_C ON C.`id_category` = P_C.`id_category`
LEFT JOIN
Product P ON P.`id_product` = P_C.`id_product`
GROUP BY C.`id_category`
Hope this helps.

selecting from multiple tables with counter

I have two tables one holds a category with column catID,catName and the other has the catID as a foreign key, now i want to select all the total items on the second table based on their catID.
E.g. What is the total number of individual element if their category is 1,2,3,4 etc. Pls code hints will help thanks.
SELECT
c.cat_id
,count(*) as occurence
FROM category c
INNER JOIN table2 t ON (c.cat_id = t.cat_id)
GROUP BY c.cat_id
If you want the categories with occurence = 0 then do:
SELECT
c.cat_id
,count(t.cat_id) as occurence
FROM category c
LEFT JOIN table2 t ON (c.cat_id = t.cat_id)
GROUP BY c.cat_id
Links:
http://dev.mysql.com/doc/refman/5.5/en/group-by-functions.html
http://www.1keydata.com/sql/sqlgroupby.html
SELECT catName, COUNT(table2.catId) FROM table1,table2
WHERE table1.catId=table2.catId
GROUP BY catName