Linked Tables and SQL SELECT Queries - php

I have a few linked tables in my custom forum: categories, sub_categories and posts
basically, I have people able to add up to three categories and five sub-categories when they make a new post.
I also enable people to 'listen' to certain categories and sub-categories and have them in an easy to access bar at the side of the page.
My tables are set up thus (only showing relavent fields for ease):
posts:
id INT
category_id VARCHAR(12)
sub_category_id VARCHAR(35)
categories:
id INT
name VARCHAR(20)
sub_categories:
id INT
name VARCHAR(20)
in my posts table, I store the set categories and sub-categories by their ID in the following format:
category_id [2][4][8]
sub_category_id [1][2][3][4][5]
thus enabling me to execute the following query in PHP and get the post based on category and sub-category:
SELECT * FROM posts WHERE category_id LIKE '%[{$id}]%' AND sub_category_id LIKE '%[{$id2}]%'
the problem I have is selecting the sub_categories for the access bar that people 'listen' to...
$sql = "SELECT title, id FROM categories";
$query = mysql_query($sql);
$list = array();
while ($row = mysql_fetch_assoc($query)){
$list[$row['title']] = array();
$sql = "SELECT sub_categories.title FROM sub_categories, posts WHERE (category_id LIKE '%[{$row['id']}]%') AND (????) LIMIT 0,100";
$query = mysql_query($sql);
while($result = mysql_fetch_assoc($query)){
$list[$row['title']][] = $result['title'];
}
}
print_r($list);
Obviously you can see where I am stuck (????), but before I explain what I am trying to do, I'll explain what the output I am looking for is.
when I print the $list array, I want it to print a multi-dimensional array featuring the categories as the first key, with their values being an array of sub-categories that have been tagged in the main category.
The problem I have is that in my sub_category_id field on the post table, remember the values are stored in the format [1][2][3] and I need to check the value against the subcategory field id.
I have tried the following:
"SELECT sub_categories.title FROM sub_categories, posts WHERE (category_id LIKE '%[{$row['id']}]%') AND (sub_category_id LIKE '%[sub_categories.id]%') LIMIT 0,100"
But it didn't work. I don't know whether there is an error in my query or whether it even SHOULD work, but I would be grateful if anyone could tell me how to do it or where I am going wrong in my code!
NB. I am trying to find which sub_categories appear in which categories based on people tagging them in a post together.

You're facing problems because you're not aware about few concepts in database...
In your case, you want to create associations called "many-to-many".
It means that a category can be used in many post and a post can be represented by many category.
To translate that into a "SQL" world, you have to create an intermediate table.
this table will store both identifier of the two tables.
for exemple:
-------------------
| categorisation |
-------------------
| post_id | => is the link to posts
| category_id | => is the link to categories
-------------------
When you create a new post, you create a new object in the table post. But you also create N records in the table categorisation.
When you want to retrieve which categories applied to this post, you can do a query like that:
SELECT post.id, post.name
FROM post
INNER JOIN categorisation on (post.id = categorisation.post_id)
INNER JOIN category ON (categorisation.category_id = category.id)
I think you need to read some articles on the web about database before progressing in you project ;)

Related

editing the category of the posts in php mysql

I have categories in my blog and i want the result if you edit the category name, then category names of the posts will change as well
if(isset($_POST['update_cat'])){
$cat_id = $_POST['cat_id'];
$cat_name = $_POST['cat_name'];
$var=mysqli_query($con,"UPDATE category SET category_name = '$cat_name' WHERE category_id = $cat_id");
if ($var) {
$var2=mysqli_query($con,"UPDATE post INNER JOIN category on post.postCategory=category.category_name SET postCategory = '$cat_name' WHERE postCategory = $cat_name");
}
There are two options for this:
1) You should create two database tables. One for category and one for posts, such that the ID(primary key) of the Categories table should be referenced from category_id(foreign key) of the posts table. The category name(which is in the category table), whenver changed, all posts that refer that corresponding ID, shall also bear the new name.
2) If you are maintaining a category_name as a column in the posts table, then you should use an after update trigger on the category table, such that whenever a category name changes, the trigger changes all the category_names in the Posts table.
The first option is the correct way of proceeding as the second might bring a lot of inconsistency in your records.

Finding a list inside a list

I'm having an issue with finding related database rows that aren't specifically linked. Lets say we have 5 tables.
Products
Id | name
Product_tags
Id | product_id | tag_id
Tags
Id | name
Blog
Id | name
Blog_tags
Id | blog_id | tag_ids
So what I do is I grab a product, with this grab the tags this product has via the Product_tags table. Say I get something like this.
Product 101
Tags 123,124,125,126
Now I have this product page. The thing is, now I want to find a blog if it fits this product, but it doesn't need to have all tags that product has, product just needs to have all that blog has. So if blog has tags 124 and 126 it needs to match. Currently I save all the tags a blog has in one row (comma seperated) but this could be changed to save 1 tag per row if needed. If it was reversed I could do it but I need to check for a partial list in a different table.
Product 101
Tags 123,124,125,126
Should find
Blog 201
Tags 124,126
But not
Blog 202
Tags 120,124
I tried a few ways but I couldn't find a way to make this work, my closest attempt was a reverse like like this.
select * from Blog_tags where "'".implode(",",$tagIds)."'" LIKE concat("%", tag_ids, "%")
This sort-of worked but not for when the product had 1,2,3 and the blog only had 1,3.
This is untested and only from memory, so feel free to comment and tell me if it doesn't work.
First of all, normalize your tag list, do not use comma-separated string. You said this could be changed, so I'm going work to assume it's one row per tag, and the column name is tag_id.
Let's start by finding the blogs having some of the tags of you product 101.
SELECT *
FROM Blog
JOIN Blog_tags ON Blog.Id = Blog_tags.blog_id
WHERE tag_id IN (123,124,125,126)
GROUP BY Blog.Id
Now this query will also include blogs that have tags not in this list. So we need to remove them. I think something like that could work:
SELECT *
FROM (
SELECT Blog.id as blogId
FROM Blog
JOIN Blog_tags ON Blog.Id = Blog_tags.blog_id
WHERE tag_id IN (123,124,125,126)
GROUP BY Blog.Id
) as Blog_filtered
LEFT JOIN Blog_tags ON Blog_filtered.blogId = Blog_tags.blog_id AND Blog_tags.tag_id NOT IN (123,124,125,126)
WHERE Blog_tags.id IS NULL
GROUP BY Blog_filtered.blogId

Get Topics from multiple Category and show top ten topics with responses in mysql/php

Hi friends i am listing topics in php which may be associated with multiple category
my db schema is
topics
topic_id
user_id
topic_name
category
category_id
category_name
topic_category (for association)
tc_id
topic_id
category_id
topic_response // for results
tr_id
topic_id
response ( given in a form of 5 star rating so its in range of 1-5 always )
user_id
what i need to do is
1st ) list top ten topics based on responses ya it will be based on count of responses
i tried ->
select t.* ,count(tr.response) as votes from topics t , topic_response tr where t.topic_id=tr.topic_id group by tr.topic_id order by votes LIMIT 10
not working
2nd) user will be shown list of topic . he can choose the category in which he wants that can be multiple too.
for example
if he chooses category_id 1,2,3,4 then topics listed in this category will be listed.
i have tried to
select t.* from topics t ,topic_category tc where tc.topic_id = t.topic_id and category_id IN (1,3,2,4)
// not able to get idea on this i would prefer if i could do this in subquery since i also need to check if the user has already responded to that question .
**3) in case if i get a query working suppose .
from php side i will be getting an array of category_id from select multiple dropdown
like array(1,2,3,4)
so i was thinking how will make this query accept category id
in form of category_id IN (1,3,2,4) in mysql query**
**can i directly pass an array like
category_id IN ($ids) where $ids is an array**
i am a newbie in mysql please help me
you help will be appreciated :)
For the first question:
You have to use LEFT JOIN and match (response's topic id row) to (topic's id) then count(response's topic id) and GROUP everything by (response's topic id).
for example:
Responses Table = responses
response_id
topic_id
response_message
Topics Table = topics
id
title
content
The query is
SELECT topics.title,topics.content,COUNT(responses.topic_id) AS count FROM topics
LEFT JOIN responses ON topics.id = responses.topic_id GROUP BY count LIMIT 10
For question 2:
You can try using AND ( IN 1 OR 2 OR 3 OR 4
You can try using BETWEEN 1 AND 4
WHERE(category_id>=1&&category_id<=4)

Query issue in Yii

Yii beginner here. I am facing some problem with how to query the database with the scenario I have. Here is what my two tables look like. The reason category is maintained in a separate table is because a product can belong to multiple categories.
Product Table
-------------
id
product_name
product_desc
product_color
product_price
Category Table
--------------
id
product_category
product_id
A product can belong to multiple category.
Now, let's say I want to find the products of category 'xyz' with color 'blue'. I am not sure how do I query both the tables using two different models (or not) to achieve this. Any help?
Here you have many to many relationship where one product can belong to multiple categories and one category can belong to multiple products.
You will definitely need a third table
Product Table
-------------
id
product_name
product_desc
product_color
product_price
Category Table
--------------
id
category_name
Product_Category Table
----------------------
product_category_id
product_id ( foreign key to Product->id )
category_id (foreign key to Category->id )
You can implement simple query without having a model like this:
$connection=Yii::app()->db;
$sql = "SELECT .....";
$command = $connection->createCommand($sql);
$dataReader=$command->query();
$rows=$dataReader->read();
print_r($rows);
Arfeen's solution is perfectly valid.
Although, I would assume that you have already read the official Relational Active Record documentation on yii website.

MySQL Select list In Array

Each Article can have unlimited categories.
Categories are saved in the database like this
example article_category: '1','3','8'
OR
example article_category: '2','3'
So when I search for a listing under, lets say category 3
$category_id = $_REQUEST['category_id']; //3
$SQL = "SELECT * FROM ARTICLES WHERE article_category = '$category_id'";
If it were just one the above would work fine.
I hate to say it but I'm completely lost.. Would I use IN ?
= (equals) check against the complete string. what you want to do could be done using LIKE and the % comodin (it's like * for files in dir or the like)
$SQL = "SELECT * FROM ARTICLES WHERE article_category LIKE \"%'$category_id'%\"";
however, i reccommend that you normalize the database and have categories as a subtable
The way I would implement this is by creating a table for categories, which you probably already have. Something like:
cat_id cat_name
1 animals
2 sports
3 locations
Then create a table to link articles to categories. Something like:
table artcat
article_id cat_id
1 1
1 3
2 1
2 2
2 3
The above table basically replaces the field article_category you have currently. In the above example
article 1 is linked to categories 1 and 3
article 2 is linked to categories 1, 2 and 3
And when you need to get all the articles for a given category, all you would run a query like:
SELECT article_id FROM artcat WHERE cat_id=3
You could even do a join with articles database to output the article titles if you wish.
I hope this helps. Good luck!
You can use FIND_IN_SET here, but it may not be very efficient. I suggest that you change your table structure and follow #jdias' answer.
If your article_category is saved as 1,2,3:
$SQL = "SELECT * FROM ARTICLES WHERE FIND_IN_SET('$category_id', article_category)";
Or if it's saved as '1','2','3':
$SQL = "SELECT * FROM ARTICLES WHERE FIND_IN_SET('\'$category_id\'', article_category)";

Categories