how to combine these two queries into one - mysql

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.

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

SQL Multiple Joins multiple where

I have three tables is question. categories, vocabulary & tex. I am trying to figure out how to have multiple joins in my query, i thought you can just add as many joins as you wanted, as long as you reference them properly.
So, the following two work perfectly on there own:
1.
SELECT
categories.ID AS ID,
categories.ParentID AS ID,
vocabulary.value AS Name
FROM categories
INNER JOIN vocabulary
ON categories.sid=vocabulary.sid
WHERE vocabulary.langid=1
2.
SELECT
categories.ID AS ID,
categories.ParentID AS ID,
tex.value AS Description
FROM categories
INNER JOIN tex
ON categories.tid=tex.tid
WHERE tex.langid=1
However, if i try to combine them as follows, it does not work.
categories.ID AS ID,
categories.ParentID AS ID,
vocabulary.value AS Name
tex.value AS Description
FROM categories
INNER JOIN tex
ON categories.tid=tex.tid
WHERE tex.langid=1
INNER JOIN vocabulary
ON categories.sid=vocabulary.sid
WHERE vocabulary.langid=1
Any ideas?
Thanks in advance
John
In MySQL, when you have columns with the same name, one of them will only be shown. You need to identify them uniquely by supplying ALIAS. And you can either put the condition on the ON clause or WHERE clause which could yield the same result since it uses INNER JOIN.
SELECT categories.ID AS CategoryID,
categories.ParentID AS CategoryParentID,
vocabulary.value AS Name
tex.value AS Description
FROM categories
INNER JOIN tex
ON categories.tid = tex.tid
INNER JOIN vocabulary
ON categories.sid = vocabulary.sid
WHERE vocabulary.langid = 1 AND
tex.langid = 1

How to write mysql subselect properly with conditions and limiting

I have three Tables:
Posts:
id, title, authorId, text
authors:
id, name, country
Comments:
id, authorId, text, postId
I want to run a mysql command which selects the first 5 posts which were written by authors, whose country is 'Ireland'. In the same call, I want to retrieve all the comments for those five posts, and also the author info.
I've tried the following:
SELECT posts.id as 'posts.id', posts.title as 'posts.title' (etc. etc. list all fields in three table)
FROM
(SELECT * FROM posts, authors WHERE authors.country = 'ireland' AND authors.id = posts.authorId LIMIT 0, 5 ) as posts
LEFT JOIN
comments ON comments.postId = posts.id,
authors
WHERE
authors.id = posts.authorId
I had to include every field with an alias ^ because there was a duplicate for id, and more fields in future may become duplicates as I'm looking for a generic solution.
My two questions are:
1) I am getting a duplicate field entry from within my subselect for id, so do I have to list out all my fields as aliases again within the subselect or is there only one field I need for a subselect
2) Is there a way to auto-alias my call? At the moment I've just aliased every field in the main select but can it do this for me so there are no duplicates?
Sorry if this isn't very clear it's a bit of a messy problem! Thanks.
You are doing an unnecessary join back to the author table in your query. You get all the fields you want in the posts subquery. I would rename this to something other than an existing table, perhaps pa to indicate posts and authors.
You say you want the first 5 posts, but have no order clause. A better form of the query is:
SELECT pa.id as 'posts.id', pa.title as 'posts.title' (etc. etc. list all fields in three table)
FROM (SELECT *
FROM posts join
authors
on authors.id = posts.authorId
WHERE authors.country = 'ireland'
order by post.date
LIMIT 0, 5
) pa LEFT JOIN
comments c
ON c.postId = pa.id
Note that this returns the first five posts and their authors (as specified in the question). But one author may be responsible for all five posts.
In MySQL, you can use * and it will get rid of duplicate aliases in the from clause. I think this is dangerous. It is better to list all the columns you want.
To answer your questions:
You can select as many (or as few) columns as you need from a sub-query
You do not need to join the authors table again since you already selected all fields in the sub-query (and so get rid of duplicate columns names).
A few additional remarks...
... about the JOIN syntax
Prefer the form
FROM t1 JOIN t2 ON (t1.fk = t2.pk)
to the obsolete, obscure
FROM t1, t2 WHERE t1.fk = t2.pk
... about the use of a LIMIT clause without an ORDER BY clause
The order in which rows are returned by a SELECT statement without an ORDER BY clause is undefined. Therefore, a LIMIT n clause without an ORDER BY clause could return any n rows in theory.
Your final query should look like this:
SELECT *
FROM (
SELECT *
FROM posts
JOIN authors ON (authors.id = posts.authorId )
WHERE authors.country = 'ireland'
ORDER BY posts.id DESC -- assuming this column is monotonically increasing
LIMIT 5
) AS last_posts
LEFT JOIN comments ON ( comments.postId = last_posts .id )

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 can I join these two queries?

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