I have three tables: categories, content_info, and content.
The categories table contains the category's id and the ID of its parent category.
The content_info contains two columns: entry_id for the post's ID and cat_id for the ID of the post's category.
The content table contains multiple columns about the post - such as ID, title, etc.
I have a variable in the URL called parent_id which corresponds to the parent of a category. I want to list all the POSTS (not CATEGORIES) which belong to a category with a parent of the parent_id value.
For example, say the parent_id value is 5. Each post might belong to a category with an ID of 20, but that category belongs to the parent category (whose ID is 5). I want to list all the posts who belong to categories with a parent value of whatever the current parent_id happens to be.
Is there a way of doing this with MySQL joins instead of changing the PHP?
This should do it:
SELECT c.* FROM content
JOIN content_info ci ON ci.entry_id=c.id
JOIN categories cat ON cat.id=ci.cat_id
WHERE cat.parent_id=<parent_id>
This return all posts (content rows) which belong to a category which parent is parent_id
Or with subqueries:
SELECT c.* FROM content
JOIN content_info ci ON ci.entry_id=c.id
WHERE ci.cat_id IN (SELECT id
FROM categories cat
WHERE cat.parent_id=<parent_id>)
SELECT c.*
FROM content c,
categories cat,
content_info ci
WHERE c.id = ci.entry_id
AND cat.id = ci.cat_id
AND cat.parent_id = 5
Related
I'd like to build an administration page for my website, where I could use multiple checkboxes to store / updates many categories for a single post.
So I've created three tables:
POST Table (id (index, auto-increment, not null), subject, content)
CATEGORIES Table (id (index, auto-increment, not null), name)
POST_CATEGORIES Table (id (index, auto-increment, not null), id_cat (foreign key to CATEGORIES.id), id_post (foreign key to POST.id))
(This last table is building relations between the posts and its categories.)
So I'm trying to list the categories with multiple checkboxes. I'm doing this query, but it doesn't work as expected:
$select = $db->query('SELECT categories.id, categories.name, post_categories.id_cat AS fk_cat, post_categories.id_post AS fk_post, post.id AS post_id
FROM `categories`
LEFT JOIN post_categories
ON categories.id = id_cat
LEFT JOIN posts
ON post.id = id_post');
Result is i have a list of categories, but each category name is repeated depending on the number of posts having this category (e.g : if post 1 and post 2 have both category 1, category 1 will appear 2 times in my list).
EDIT :
Thanks for the replies, here is a sqlfiddle to see what's happening...
http://sqlfiddle.com/#!9/4c304/1
(I'm trying to display a list of categories. I won't select * from categories table because in a next step, i'd like the right categories to be checked when i edit a post.)
SELECT DISTINCT c.id
, c.name
, p.id post_id
FROM categories c
LEFT
JOIN post_categories pc
ON c.id = pc.id_cat
LEFT
JOIN posts p
ON p.id = pc.id_post
If i use GROUP BY categories.id, i don't have doubles anymore...
But it only keeps the first post which is "tagged" with the current category. I need to keep all those informations.
Maybe i should filter by a php query? Something like if count(category.id > 1) then only display the one where post_id = current post edit? (sorry if it's not clear, i feel a bit confuses :( )
I am working on an e-commerce site from scratch using PHP and MYSQL. I have one table for categories, with a column for ID and a column for Parent_ID.
When displaying the products on categories.php, I have it set to display products where the Parent_ID OR the ID equals the $_GET['id'] field. But now I've run into a problem.
In my "Groceries" category, I have the "Cleaning & Home" subcategory, and under "Cleaning & Home" I have several categories like "Laundry", "Bathroom Supplies", etc.
My problem is that products in the third level don't display in the "Groceries" category, because technically the parent ID of "Laundry" is "Cleaning & Home". There will never be more than three levels (Parent, child, grandchild), but I would like categories in the grandchild level to also display in the parent level.
I've tried looking through MYSQL documentation and on other forums but so far no luck.
This requires a couple of joins to get to the top parent:
select c.*,
coalesce(cp2.id, cp.id, p.id) as MostParentId
from categories c left outer join
categories cp
on c.parent_Id = cp.id left outer join
categories cp2
on cp.parent_id = cp2.parent_id
where c.id = $_GET['id'] or cp.id = $_GET['id'] or cp2.id = $_GET['id'];
You can then compare the ids using or for a match to the parent category, subcategory, or whatever.
Okay so I have two tables, a category table and a posts table.
I was hoping to construct a query that would return each category, the last record in the post table for that category (category.id = post.category_id) AND the rowcount of all posts with post.category_id = category.id)
i.e
A list of categories, each with the record of the latest post for the category and the number of posts in that category.
I've tried various joins and subselects, and I have managed to get a list of categories, their post count, and their FIRST post (I need the last).
I have also managed to get a list of categories and their LAST post, but not the post count.
Any help/directions will be much appreciated!
Try this:
SELECT category_id, MAX(post_id) AS post_id, COUNT(*) AS posts
FROM post
GROUP BY category_id
This assumes that you have a column post_id that is strictly increasing and unique.
If you have no such field but you have for example post_date that is not unique, you may get two rows for some categories in rare cases where two posts have exactly the same timestamp.
To also get categories without posts use a LEFT JOIN:
SELECT
category.id AS category_id,
MAX(post.id) AS post_id,
COUNT(post.category_id) AS posts
FROM category
LEFT JOIN post
ON category.id = post.category_id
GROUP BY category.id
If you need more columns from each table you can join the result above with the original tables:
SELECT *
FROM
(
SELECT
category.id AS category_id,
MAX(post.id) AS post_id,
COUNT(post.category_id) AS posts
FROM category
LEFT JOIN post
ON category.id = post.category_id
GROUP BY category.id
) T1
JOIN category
ON T1.category_id = category.id
LEFT JOIN post
ON T1.post_id = post.id
Your descriptions lacking a bit of data (I've made assumptions), but the SQL should be:
SELECT category_id,max(postdate) last,count(id) postcount
FROM posts
GROUP BY category_id
If you need something from the category table then you'll just need to join that in.
Assumptions:
There's a column called postdate in your posts table that reflects the date a post was generated (and so the maximum one is the most recent). You could also do max(id) if there are no dates... although only if there's no change a past post could be updated so it's effectively the more recent (eg id=2 created last week,updated today, id=3 created yesterday).
There's a column called id - a unique id for each post row.
If you need the content of the last post you need to join this back to the posts table.
I have some items, each item has a category and a sub-category. What is the best way to organize this in mysql ?
Create a table
catID
CategoryName
ParentCategory ....any other fields
Parent Category column will store the catID of Parent category if any.
or
CategoryTable
catID
CategoryName
CategoryRel Table
----------------------------------
ID
catID
SubcatID
where catID and subCatID are the IDs from category table.
First, you have a big decision to make. Will you design your database so that there are only two levels of category? Or will you allow for more than two levels in the future?
If you are willing to accept a permanent limit of category and sub-category, you can add two tables. Categories will list the allowed categories. Subcategories will list the allowed Subcategories and what Category they belong to. And your data table will include only the Subcategory. (If there is no information about a category other than its name, you could dispense with the Categories table and just include the category name in the Subcategories table.)
If you want to allow any number of levels, you will have only a single Categories table. Each row will have the category name and another column with the parent category. Your data table will still include a single category column.
categories
-----------
id
title
description
subcategories
-------------
id
title
description
category_id
items
-----------
id (*i had misspelled id as 'if'. corrected it here)
title
description
subcategory_id
I have a categories table set up as so [id, name, parent_id] and a items table [id, name, category_id, visible]. What I'm trying to do is create a query that will return all the ids of all non-empty categories, non empty being that it or one of it's children has at least one item belonging to it. What would be the best way to do this in MySQL?
edit
SELECT DISTINCT category_id FROM Items
This works for categories containing items, but I also need the parent categories of all item containing categories. This query will be used as a subquery along with some other filters.
Top Level Category
->Second Level Category
-->Third Level Category
--->Item 1
--->Item 2
Maybe off topic, but I think it is still worth referencing: Extensive Article on Managing Hierarchical Data in MySQL.
All non-empty categories, and only those, have items with category_id pointing at them, therefore you could just select category_ids from items table:
SELECT DISTINCT category_id FROM Items
As far as I know, you can't select all the ancestors of these categories in one query, however you might want to use another tree model.
With the nested set model, your query could look like this:
SELECT DISTINCT c.id FROM Categories c JOIN Items ON c.id = category_id JOIN Categories ancestors ON c.lft BETWEEN ancestors.lft AND ancestors.rgt
I'm not sure if it'll work, but you can try.