How can I join these two queries? - mysql

Here's what I want to accomplish:
Select all rows from table "posts" while also fetching linked entities, such as the author (from table "users") and the names of the categories the post belongs to (from table "categories").
These are my two queries so far:
This one fetches the posts:
SELECT
posts.*
, users.authorName AS author
FROM posts
INNER JOIN users
ON users.id = posts.author
And this one fetches a comma separated list of categories for a specific post:
SELECT
GROUP_CONCAT(categories.category) AS categories
FROM categories
INNER JOIN post_category
ON post_category.categoryID = categories.id
WHERE
post_category.postID = ?
The two queries on their own work fine.
Naturally when the two are combined, I wouldn't need the WHERE clause of the second query.
I tried using the second query as a sub-query within the first one's SELECT clause, but that fetched a comma separated list of ALL categories for ALL posts. I want only the categories for the post I'm currently iterating over.
Any help would be greatly appreciated, and I apologize if any of this is unclear - it's hard enough for me to think about, let alone describe to other people ;)

Something like this:
SELECT posts.*, users.authorName AS author,
GROUP_CONCAT(categories.category) AS categories
FROM posts, users, categories, post_category
WHERE users.id = posts.author
AND post_category.categoryID = categories.id
AND post_category.postID = posts.id
GROUP BY posts.* /* list actual columns here */, author
Or did I miss something?

I think your subquery approach should work fine, but you still need the where clause in your subquery. How else would MySQL know which rows to retrieve? Try:
SELECT posts.*, users.authorName AS author,
(SELECT GROUP_CONCAT(categories.category)
FROM categories
INNER JOIN post_category ON post_category.categoryID = categories.id
WHERE post_category.postID = posts.postID) AS categories
FROM posts
INNER JOIN users ON users.id = posts.author

Related

MySQL Query returning same row twice

I am trying to display data using 3 tables
posts
- id
- category_id
- user_authors_id
- title
- status
user_authors
- id
- author_name
categories
- id
- name
subcategories
- id
- name
What I am trying to do is. I am creating a view panel that will display the posts. So, i am using 3 tables. From user_authors I'll get the author name, from categories table I'll get the category name, now the category tables have subcategory id, so I also want to get the subcategory name.
I am having two rows in the posts table with id 29 and 30 but when i run the below query it shows 2 entries with the same data.
SELECT
posts.id,
categories.name AS cat_name,
subcategories.name AS subcat_name,
posts.title,
user_authors.author_name,
posts.created,
posts.status
FROM posts
INNER JOIN user_authors ON (user_authors.id = posts.user_author_id)
INNER JOIN categories ON(posts.category_id = categories.id)
INNER JOIN subcategories ON (categories.id = subcategories.category_id)
But, if I remove this statement INNER JOIN subcategories ON (categories.id = subcategories.category_id) and run the query, it runs perfect, all the rows are shows properly.
What's happening, I am not trying to get it. Where is the query wrong, also it's showing no error.
INNER JOIN subcategories ON (categories.id = subcategories.category_id)
As it is, for your query to return what you expect, there must be one and only one record in subcategories matches the given post :
if more than one subcategory matches a given post, the post line will be duplicated in the results
if no subcategory matches a given post, the post will not appear in the results
Depending on your use case, you want :
not to JOIN subcategory, to avoid duplicating posts
LEFT JOIN subcategory instead of INNER JOIN subcategory to avoid posts without subcategory to be filtered out
If you do have multiple subcategories for a given post and you still want to display a single row in the results, you can use the GROUP_CONCAT aggregate funtion to concatenate the subcategories into one field :
SELECT
posts.id,
categories.name AS cat_name,
GROUP_CONCAT( subcategories.name, ', ') AS subcat_names,
posts.title,
user_authors.author_name,
posts.created,
posts.status
FROM posts
INNER JOIN user_authors ON (user_authors.id = posts.user_author_id)
INNER JOIN categories ON(posts.category_id = categories.id)
LEFT JOIN subcategories ON (categories.id = subcategories.category_id)
GROUP BY
posts.id,
categories.name,
posts.title,
user_authors.author_name,
posts.created,
posts.status

How to compare data in two tables and display data from one table

I have 2 tables with the following structure:
categories
id
status
name
created
posts
id
status
category_id
title
excerpt
featured_image
created
user_authors
id
status
author_name
created
I am using the following query:
$query = "SELECT posts.id, posts.category_id, user_authors.author_name, posts.user_author_id, posts.title, posts.post_slug, posts.featured_image, posts.excerpt, posts.created FROM posts, user_authors INNER JOIN categories ON(posts.category_id = categories.id) WHERE posts.status = 1 AND categories.name LIKE = %".$_GET['category']."%";
What i am trying to do is, i am having an url www.xyz.com/technology
where technology is a parameter(category) according to that i will select the posts to display.
I am showing the data where posts.category_id = categories.id AND category_name = $_GET['category']
I am not able to extract any data, I am confused that whether my query is wrong or my logic is wrong?
Can anyone help me solving this logic?
You can not use = with LIKE clause and you did not write any relation between posts and user_authors tables.
The correct query should be:
$query = "SELECT posts.id, posts.category_id, user_authors.author_name, posts.user_author_id, posts.title, posts.post_slug, posts.featured_image, posts.excerpt, posts.created FROM posts INNER JOIN user_authors ON (user_authors.id = posts.user_author_id) INNER JOIN categories ON (posts.category_id = categories.id) WHERE posts.status = 1 AND categories.name LIKE '%".$_GET['category']."%'";
If you are finding only for one categories.name you can remove % from query, this will help mysql to search records if categories.name column has index.
Consider removing the user_author from the select, as there is no join to link the three tables in your command.
Your query has a = with LIKE which is not correct in mysql. The correct way should be,
categories.name LIKE '%". $_GET['category']."%'"
Note the removal of = and enclosing with '
Edit:
According to your reply the new query should look like below.
SELECT posts.id, posts.category_id, user_authors.author_name, posts.user_author_id, posts.title, posts.post_slug, posts.featured_image, posts.excerpt, posts.created
FROM posts INNER JOIN categories ON posts.category_id = categories.id
INNER JOIN user_authors ON posts.id = user_authors.id
WHERE posts.status = 1 AND categories.name LIKE '%".$_GET['category']."%'"

mysql query with multiple left join in 3 tables?

i have a search query which will retrieve information from 3 tables i made the query so it retrieve the information from 2 tables and i don't know if i can combine the third one or not
SELECT *
FROM articles
INNER JOIN terms
ON articles.ArticleID = terms.RelatedID AND terms.TermType = 'article'
the third query is
SELECT * FROM categories where CategoryID in (something)
something is a filed in the articles tables which have value like '3,5,8'
i want do this 2 queries into 1 query and i don't know if it can be done by 1 query or not
without looking at your schema (which would be helpful) and some sample data try this query
SELECT *
FROM categories,articles
INNER JOIN terms
ON (articles.ArticleID = terms.RelatedID AND terms.TermType = 'article')
WHERE
FIND_IN_SET(categories.CategoryID,articles.categories)
here is the definition for FIND_IN_SET()
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set
If i understand you correctly. Looks like you have multiple categories for each article with the Category IDs all stored as a concatenated string.
SELECT A.*
FROM articles A
INNER JOIN terms T on A.ArticleID = T.RelatedID AND T.TermType = 'article'
LEFT JOIN categories C on C.CategoryID IN (3,5,8 OR A.CategoryIDs)
GROUP BY C.CategoryName
You want to LEFT JOIN since you may or may not have multiple categories, you can group by Categories to get disticnt category article pairs and CONCAT() to recombine article records as needed.

how to combine these two queries into one

I have three tables: posts, cat_collection, and cat_mapping
posts contains the fields you would expect to see in a table named posts
id, type, title, body, author, email, date, ect..
cat_collection contains id, name, description
cat_mapping contains *id, collection_id, post_id*
I currently have two queries, the first one selects the information from posts, the second retrieves the associated categories from cat_collection and cat_mapping
first
SELECT post.id, post.type, post.title, post.body, post.date, post.author, post.email
FROM posts AS post
WHERE post.id = 1
second
SELECT cat.name
FROM cat_collection AS cat
LEFT JOIN cat_mapping AS map ON map.collection_id = cat.id
WHERE map.post_id = 1
Is there a way to return all of the post information, as well as the list of associated categories with a single query?
If I understand your data model, you just need another left join. You may want to re-order the joins to make sure that your query is efficient and returns the right data.
SELECT
posts.id,
posts.type,
posts.title,
posts.body,
posts.date,
posts.author,
posts.email,
cat.name
FROM
posts
LEFT JOIN
cat_mapping AS map ON map.post_id = posts.id
LEFT JOIN
cat_collection AS collection ON map.collection_id = collection.id
WHERE
posts.id = 1
Please think carefully about your aliases. Aliasing "posts" to "post" is silly. Aliasing "cat_collection" to cat is confusing - the table is about collections of cats, not cats.

MySQL Multiple Left Joins

I am trying to create a news page for a website I am working on. I decided that I want to use correct MySQL queries (meaning COUNT(id) and joins instead of more than one query or num_rows.) I'm using a PDO wrapper, that should function fine, and this still fails when run directly through the MySQL CLI application.
Basically, I have 3 tables. One holds the news, one holds the comments and one holds the users. My aim here is to create a page which displays all (will paginate later) the news posts titles, bodies, authors and dates. This worked fine when I used a second query to get the username, but then I decided I'd rather use a JOIN.
So what's the problem? Well, I need two joins. One is to get the author's username and the other to get the number of comments. When I simply go for the author's username, all works as expected. All the rows (there are 2) in the news table are displayed. However, when I added this second LEFT JOIN for the comments row, I end up only receiving one row from news (remember, there are 2,) and COUNT(comments.id) gives me 2 (it should display 1, as I have a comment for each post.)
What am I doing wrong? Why is it only displaying one news post, and saying that it has two comments, when there are two news posts, each with one comment?
SELECT news.id, users.username, news.title, news.date, news.body, COUNT(comments.id)
FROM news
LEFT JOIN users
ON news.user_id = users.id
LEFT JOIN comments
ON comments.news_id = news.id
Also, just to be sure about one other thing, my left join to comments is the correct way to get all posts regardless of whether they have comments or not, correct? Or would that be a right join? Oh, one last thing... if I switch comments.news_id = news.id to news.id = comments.news_id, I get 0 results.
You're missing a GROUP BY clause:
SELECT news.id, users.username, news.title, news.date, news.body, COUNT(comments.id)
FROM news
LEFT JOIN users
ON news.user_id = users.id
LEFT JOIN comments
ON comments.news_id = news.id
GROUP BY news.id
The left join is correct. If you used an INNER or RIGHT JOIN then you wouldn't get news items that didn't have comments.
To display the all details for each news post title ie. "news.id" which is the primary key, you need to use GROUP BY clause for "news.id"
SELECT news.id, users.username, news.title, news.date,
news.body, COUNT(comments.id)
FROM news
LEFT JOIN users
ON news.user_id = users.id
LEFT JOIN comments
ON comments.news_id = news.id
GROUP BY news.id