MySQL subquery error on multiple tables - mysql

I have 3 tables posts, terms and relationships.
posts table:
ID title
1 abc
2 cdf
terms table:
term_id slug
1 jeans
2 shirts
relationships table:
object_id taxonomy_id
1 1
2 1
The MySQL query I used to try to list the titles which have "jeans" related to them
SELECT posts.title
FROM posts, terms, relationships
WHERE (SELECT terms.term_id FROM terms WHERE terms.slug LIKE '%jeans%')
AND (SELECT relationships.object_id FROM relationships WHERE terms.term_id = relationships.taxonomy_id)
AND (posts.ID = relationships.object_id)
It gives me error #1242 - Subquery returns more than 1 row. How can I fix this?

Try this:
SELECT posts.title
FROM posts INNER JOIN relationships ON (posts.ID = relationships.object_id)
INNER JOIN terms ON (terms.term_id = relationships.taxonomy_id)
WHERE terms.slug LIKE '%jeans%';
I don't have your tables, so I can't test, but I think this should work.

Try something like this:
SELECT p.title
FROM posts p
JOIN relationships r
ON r.object_id = p.ID
JOIN terms t
ON t.term_id = r.taxonomy_id
WHERE t.slug LIKE '%jeans%'

SELECT posts.title
FROM posts
INNER JOIN relationships ON (posts.ID = relationships.object_id)
INNER JOIN terms ON (terms.term_id = relationships.taxonomy_id)
WHERE
(terms.slug LIKE '%jeans%')
AND
(terms.term_id = relationships.taxonomy_id)
AND
(posts.ID = relationships.object_id)

Related

MySQL query with multiple INNER JOIN

I'm a little bit confused about a stupid query:
I get rows from the table posts joined with the table authors and the table comments, in a way like this:
SELECT posts.*, authors.name, COUNT(comments.id_post) AS num_comments
FROM posts JOIN authors ON posts.id_author = authors.id_author
LEFT JOIN comments ON posts.id_post = comments.id_post
WHERE posts.active = 1
AND comments.active = 1
this doesn't work, of course.
What I try to do is to retrieve:
1) all my active post (those that were not marked as deleted);
2) the names of their authors;
3) the number of active comments (those that were not marked as deleted) for each post (if there is at least one);
What's the way? I know it's a trivial one, but by now my brain is in offside…
Thanks!
Presumably, id_post uniquely identifies each row in posts. Try this:
SELECT p.*, a.name, COUNT(c.id_post) AS num_comments
FROM posts p JOIN
authors a
ON p.id_author = a.id_author LEFT JOIN
comments c
ON p.id_post = c.id_post
WHERE p.active = 1 AND c.active = 1
GROUP BY p.id_post;
Note that this uses a MySQL extension. In most other databases, you would need to list all the columns in posts plus a.name in the group by clause.
EDIT:
The above is based on your query. If you want all active posts with a count of active comments, just do:
SELECT p.*, a.name, SUM(c.active = 1) AS num_comments
FROM posts p LEFT JOIN
authors a
ON p.id_author = a.id_author LEFT JOIN
comments c
ON p.id_post = c.id_post
WHERE p.active = 1
GROUP BY p.id_post;
Since you are doing a count, you need to have a group by. So you will need to add
Group By posts.*, authors.name
You should you GROUP BY clause together with aggregate functions. Try something similar to:
SELECT posts.*, authors.name, COUNT(comments.id_post) AS num_comments
FROM posts JOIN authors ON posts.id_author = authors.id_author
LEFT JOIN comments ON posts.id_post = comments.id_post
-- group by
GROUP BY posts.*, authors.name
--
WHERE posts.active = 1
AND comments.active = 1
I found the correct solution:
SELECT posts.id_post, authors.name, COUNT(comments.id_post) AS num_comments
FROM posts JOIN authors
ON posts.id_author = authors.id_author
LEFT OUTER JOIN comments
ON (posts.id_post = comments.id_post AND comments.active = 1)
WHERE posts.active = 1
GROUP BY posts.id_post;
Thanks everyone for the help!

Subquery vs join

SELECT
id
FROM
Posts
WHERE
subject_id = 1
OR subject_id IN (
SELECT related_subject_id
FROM RelatedSubjects
WHERE parent_subject_id = 1);
Trying to select all posts for a current subject but also for any sub-subjects which are stored in another lookup table. The above query works, wondering how to accomplish the same thing with a join
SELECT DISTINCT id
FROM Posts AS p
LEFT JOIN RelatedSubjects AS r
ON p.subject_id = r.related_subject_id AND r.parent_subject_id = 1
WHERE p.subject_id = 1 OR r.related_subject_id IS NOT NULL
Assuming proper indexes, UNION often performs better than JOIN with OR:
SELECT p.id
FROM Posts AS p
WHERE p.subject_id = 1
UNION
SELECT p.id
FROM RelatedSubjects AS r
JOIN Posts AS p
ON p.subject_id = r.related_subject_id
WHERE r.parent_subject_id = 1
select
`Posts`.`id`
From posts as `Posts`
LEFT join RelatedSubjects as `RelatedSubjects`
on (`RelatedSubjects`.`related_subject_id` = `Posts`.`subject_id`)
where `Posts`.`subject_id` = 1

MYSQL compare values from same columns

Okay I tried to look all over stackoverflow, and the closest solution I found is this:
mysql AND clause on same column multiple times
But I can't use statements and "having" syntax won't work because of group by. There MUST be a simple solution to this.
The 2 tables looks like this (simplified):
users:
uid name
1 person 1
2 person 2
3 person 3
categories:
uid value
1 actor
1 musician
2 actor
3 dancer
4 musician
4 dancer
I want to get the uid of those that are 2 values at the same time. For example, I want to get the UID that is an actor AND a musician. Not just one value, but both of them must be required!
First I tried this:
SELECT users.uid, users.name
FROM
users
LEFT OUTER JOIN categories ON users.uid = categories.uid
WHERE (categories.value = 'actor' AND categories.value = 'musician')
GROUP BY u.uid;
This of course does not work since one row can't have 2 values.
Does anyone know a solution?
You can JOIN to the categories table multiple times to get the result:
SELECT users.uid, users.name
FROM users
INNER JOIN categories c1
ON users.uid = c1.uid
INNER JOIN categories c2
ON users.uid = c2.uid
WHERE c1.value = 'actor'
AND c2.value = 'musician';
See SQL Fiddle with Demo
SELECT users.uid, users.name
FROM users
LEFT JOIN categories ON users.uid = categories.uid
WHERE categories.value in ('actor', 'musician')
GROUP BY u.uid, users.name
having count(distinct categories.value) = 2;
Use a having clause
SELECT u.uid, u.name
FROM users u
LEFT OUTER JOIN categories c ON u.uid = c.uid
WHERE c.value = 'actor' OR c.value = 'musician'
GROUP BY u.uid
having count(distinct c.value) > 1
If you really do not want to use having you could try this:
SELECT uid, name
FROM users
WHERE
uid IN (SELECT uid FROM categories WHERE value='actor')
AND uid IN (SELECT uid FROM categories WHERE value='musician')
But there is really nothing wrong with using HAVING ;)

joining 3 tables in one sql

I have 3 tables as described below ,
table1 'ads'
id userid
1 47
2 47 //ads.id = adcat.adid
3 45
4 47
table2 'adcat'
adid catid
1 1
2 3
3 3 // adcat.catid = categories.id
4 3
table3 'categories'
id name
1 mathematic
2 biolog
3 leteratur
4 chemi
What I want is to get categories.id from ads.id.
I have tried this
SELECT categories.id, ads.id
FROM ads
INNER JOIN adcat ON ads.id = adcat.adid
INNER JOIN categories ON categories.id = adcat.catid
But it does not come by the exact value.
obs : I don't get any error just not exact value.
any help will be much appreciated.
Seems to be no reason to go in to categories table if adcat.catid = categories.id and that is the only value you need.
SELECT ads.id,adcat.catid
FROM ads
INNER JOIN adcat
ON ads.id=adcat.adid
Use $row['catid'] with this query.
If in the future you need more columns from categories then you will need a double join:
SELECT categories.id *AS id*,ads.id *AS ads_id*
FROM ads
INNER JOIN adcat ON ads.id = adcat.adid
INNER JOIN categories ON categories.id = adcat.catid
Use $row['id'] with this query.
See *AS id* and *AS ads_id* - remove the stars and you are giving the columns an ALIAS which is basically like a nickname, this can be handy in many cases but especially important in this case since the two columns both have the same names. So now you can call $row['id'] and get categories.id
I'm not sure what exactly is the question but I think you are trying to get not all but single row based on one ads.id if so:
SELECT categories.id ,ads.id
FROM ads
INNER JOIN adcat ON ads.id = adcat.adid
INNER JOIN categories ON categories.id = adcat.catid
WHERE ads.id = your_id_here
Try this:
SELECT categories.id, ads.id
FROM ads, adscat, categories
WHERE ads.id=adcat.adid
AND categories.id = adcat.catid

JOIN 3 tables query

ok, here we go...
I have 3 tables: posts, comments and members, i need to get title from posts, msg from comments and username from members.
all tables has an identical ID to associate(?)
for example: i want to get these data from certain ID...
sorry for my bad english, isn't my language, and my very basic skill on MySQL (started today).
Edit:
this is my schema:
posts: |ID|title|
----------------
|1 |post title| (example data)
comments: |USERID|UID|msg| (UID is same as posts.ID)
-----------------
|5 |1 |message| (example data)
members: |USERID|username|
-----------------
|5 |myusername| (example data)
when i make a query to ID 80 (eg.) will return the title, the messages associated to that post (UID) and the username associated to that comment.
for eg. if the post 80 have 5 comments shows, title of post and username of comment.
i think this is more clear. (no?)
Maybe something like this:
SELECT P.Title, C.Message, M.Username
FROM Posts P
INNER JOIN Comments C ON P.PostID = C.PostID
INNER JOIN Memmbers M ON C.MemberID = M.MemberID
WHERE P.PostID = 123
Here it is with your schema (I think mine is better that's why I left it) :)
SELECT P.title, C.msg, M.username
FROM posts P
INNER JOIN comments C ON P.ID = C.UID
INNER JOIN memmbers M ON C.USERID = M.USERID
WHERE P.ID = 80
The post title will be repeated in this case, but I believe this is what you are asking for.
Without seeing your schema I can only guess but I think it might look something like this:
SELECT p.title, c.msg, m.username
FROM Posts p
INNER JOIN Comments c ON (p.AssociateID = c.AssociateID)
INNER JOIN Members m ON (m.AssociateID = p.AssociateID)
WHERE p.AssociateID = 123
If your schema is different, adjust the SQL above to fit your table structure.
First of all your tables structure (singular table names) should look like something like this:
post:
id
title
member_id
comment:
id
msg
post_id
member_id
member:
id
username
SELECT p.title, c.msg, m.username
FROM comment c
INNER JOIN post p ON p.id = c.post_id
INNER JOIN member m ON m.id = p.member_id
WHERE m.id = YOURUSERIDGOESHERE
You can also do something like:
SELECT P.Title, C.Message, M.Username
FROM Posts P, Comments C, Members M
WHERE P.ID = C.UID
AND C.USERID = M.USERID
AND P.PostID = 80
This will produce the same results as the JOIN several others suggested, but some people feel that the WHERE shows the relationships more clearly. This is just a matter of personal preference.