JOIN 3 tables query - mysql

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.

Related

Add count value to a SQL query?

I am making a forum page using MySQL as database, but I'm coming from MongoDB and am a bit confused. When I fetch all posts for a specific category it looks something like this
SELECT p.id, p.posted_at, p.title, p.content, c.name AS category_name, u.name
AS author_name
FROM posts AS p
INNER JOIN users AS u ON p.author = u.id
INNER JOIN categories AS c ON p.category = c.id
WHERE p.category = 3 <-- Category ID
People can follow posts so I have a table called user_post_relations which contains two columns; user_id and post_id.
My goal is to add a follower count per post to the query that's getting all the posts per category. How can this be achieved with only one query?
Add the following JOIN with sub-query to your query
JOIN (SELECT post_id, COUNT(*) follower_count
FROM user_post_relations
GROUP BY post_id) AS upr ON upr.post_id = p.id
And then add upr.follower_count to your SELECT list

Disambiguating identical columns in a join

[Yes, I've searched for an answer for this here and in google but this is a little difficult to query for.]
(MySQL database.)
messages table:
messageid
senderid
recipientid
people table:
personid
name
I wish to issue a query that returns the following:
messageid sender_name recipient_name
1 larry jane
2 mark alice
etc.
The following doesn't do it, and I expected that it would not, but it's a place to start:
select m.messageid, p.name as "sender_name", p.name as "recipient_name"
from messages m, people p
where m.senderid = p.personid and m.recipientid = p.personid
The issue is that I don't know how in sql to specifically reference the sender and the recipient since they are part of the same join clause, if that makes sense.
thanks
try:
select m.messageid, pSender.name as "sender_name", pRecipient.name as "recipient_name"
from messages m
inner join people pSender on m.senderId = pSender.personId
inner join people pRecipient on m.recipientid = pRecipient.personId
For your join method (i think this should work... i'm not very familiar with comma joins)
select m.messageid, p.name as "sender_name", p.name as "recipient_name"
from messages m, people pSender, people pRecipient
where m.senderid = pSender.personid and m.recipientid = pRecipient.personid
You can join the same table into the query twice, just alias it differently, something aking to:
select m.messageid, s.name as "sender_name", r.name as "recipient_name"
from messages m
inner join people s on m.senderid = s.personid
inner join people r on m.recipientid = r.personid
Your query return only messages that is sent from a person to itself. Something like:
select m.messageid, p1.name as sender_name, p2.name as recipient_name
from messages m,
join people p1
on m.senderid = p1.personid
join people p2
on m.recipientid = p2.personid
That is you need one join for sender and one join for receiver

Get unique records based on multi-join with conditionals

I have 4 tables: posts, users, mentions, following
posts
----------------------------
id | user_id | post_text
1 1 foo
2 1 bar
3 2 hello
4 3 jason
users
------------
id | name
1 jason
2 nicole
3 frank
mentions
--------------------------
id | post_id | user_id
1 4 1
following
-------------------------------------------------
id | user_id | user_id_of_user_being_followed
1 1 2
posts includes the user_id of the user who posted some text
users has the user id and name of the user
mentions has the post id and user id of any post which has mentioned 1 or more other users
following has a the user id and the user they are following (user can follow 0 to many users)
What I'm trying to do is return all posts from users a that a given user follows, PLUS any posts that have mentioned that user (whether or not the given user is following), without returning any duplicates.
SELECT p.id, p.post, u.name,
FROM following f
JOIN posts p ON f.following = p.user_id
JOIN users u ON u.id = p.user_id
WHERE f.user_id = :user;
The above returns all posts from users that a given user is following, but I'm struggling figuring out how to include mentions as well (remember, a user does not have to follow someone to be able to see the post they've been mention in).
UPDATE:
Thanks to John R I was able to figure this out:
SELECT DISTINCT(p.id), p.post, u.name
FROM posts p
LEFT JOIN following f ON f.following = p.user_id
LEFT JOIN mentions m ON m.posts_id = p.id
JOIN users u ON u.id = p.user_id
WHERE (f.user_id = :user_id OR m.user_id = :user_id)
if i understand your querstion correctly you would want a left join to include any mentions.. but not filter out any followers/posts
if you can add some sample data to play with I can make sure its working how you want it to...
SELECT
if(p.id is not null, p.id, p1.id) as post_id,
if(p.post is not null, p.post, p1.post) as post_text,
u.username, m.id, m.user_id
FROM posts p
JOIN users u on u.id = p.user_id
JOIN following f on f.user_id_of_user_being_followed = u.id
LEFT JOIN mentions m on m.user_id = f.user_id
LEFT JOIN posts p1 on p1.id = m.post_id
WHERE f.user_id = :user or m.user_id = :user;
I left join mentions to the post made and also when the user_id in the mention table is equal to the specified user to filter out other users. the left join shouldn't change the number of rows returned.. but only include any mentions
EDIT: WORKING FIDDLE
after playing around with it I realised it was trying to put all of the data into one row.. try this:
(
SELECT p.id, p.post_text, u.name
FROM posts p
JOIN users u on u.id = p.user_id
JOIN following f on f.user_id_of_user_being_followed = u.id
WHERE f.user_id = 1
)
UNION
(
SELECT p.id, p.post_text, u.name
FROM following f
JOIN mentions m on m.user_id = f.user_id
JOIN posts p on p.id = m.post_id
join users u on u.id = p.user_id
WHERE f.user_id = 1
);
Maybe you inherited this db; but the last table is not really in line with good data normalization. The table should be the id and following_id; as set up you'll eventually run out of columns (or have to keep adding them when a user gets an error) - new users won't be able to follow anyone.

Sql Count on many to many

I have three tables
post
id | statement | date
features
id | feature
post_feature (many to many table between Post and Feature)
post_id | feature_id
I want to fire a query that will give me count of different distinct features and its respective features for the posts that are in given date period. I have just started learning SQL and I am not able to crack this one.
I tried the following one but not getting correct results.
SELECT f.feature, count(f.feature)
FROM post_feature l
JOIN features f ON (l.featureid = f.id AND l.featureid IN (
select post.id from post where post.date > 'some_date'))
GROUP BY f.feature
You can try like this:
SELECT f.feature, count(f.feature)
FROM post_feature l
JOIN features f ON l.featureid = f.id
JOIN post p ON l.post_id =p.id
WHERE p.date > 'some_date'
GROUP BY f.feature
select f.feature, count(*)
from post_feature l inner join features f on l.feature_id = f.id
inner join post p on l.post_id = p.id
where p.date > 'some_date'
group by f.feature
Your SQL is quite creative. However, your join in the IN clause is on the wrong columns. It should be on postid to postid.
Although that fixes the query, here is a better way to write it:
SELECT f.feature, count(f.feature)
FROM post p join
post_feature pf
on p.id = pf.postid join
feature f
on pf.featureid = f.id
where post.date > 'some_date'
GROUP BY f.feature
This joins all the tables, and then summarizes by the information you want to know.
Try
SELECT f.feature, count(DISTINCT f.feature)
FROM post_feature l
JOIN features f ON (l.featureid = f.id AND l.featureid IN (
select post.id from post where post.date > 'some_date'))
GROUP BY f.feature

MySQL subquery error on multiple tables

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)