Select all posts that user hasn't responded to? - mysql

I have a website that shows posts, and a user can vote on it. After they vote once I don't want it to show to that user again. So I need to have a query that polls all posts and returns the ones the user has not yet responded to.
I was thinking it would be simplest to have a posts table, responses table, and user table. The response table could include a postId, and userId. This could allow me to see all the posts that a user has responded to, but I couldn't figure out how to flip it to show the negation. Also it seems like it would be pretty slow to do it that way.

To find all posts which have not yet been seen by a given user, you could try the following query:
SELECT p.*
FROM posts p
WHERE NOT EXISTS (SELECT 1 FROM responses r
WHERE r.postId = p.postId AND r.userId = <some value>)
As an alternative to using NOT EXISTS, you could also phrase this using a LEFT JOIN:
SELECT p.*
FROM posts p
LEFT JOIN responses r
ON p.postId = r.postId AND
r.userId = <some value>
WHERE r.postId IS NULL

Related

mysql tables: Join to two tables in a request

Newbie here.. Here's what I'm trying to do.
I have a Posts table with the following columns
id, userid, bodyText, date
and I have another table for users users.
When users submit a post, the user-id saves into the "posts" table under "userid". Well, I want to display that users information, such as name and picture, on the posts using the "userid" to get each users information so that their name and picture shows along with the post they submitted.
Sorry if I'm not being clear, english is not my first language and like I said, I'm new at this and still trying to learn.
I had it where when they submit the post, their name and picture also saves into the "posts" table but I want to change it because if the user updates their name or picture, it will still show the name and picture they had when they submitted the post. I want their name and picture to update on the posts if they update their information on the users table.
What you are asking about is a JOIN. In general the Join will look like
SELECT p.id. p.bodyText, p.date, u.name, u.picture FROM posts as p INNER JOIN users as u ON p.user_id = u.id where p.id = 123;
This will select the post with the ID 123 from the posts table and joins the users information from the users table based on the user_id columns value from the posts table.
In Syntax this could be something like
$sth = $dbh->prepare("SELECT p.id. p.bodyText, p.date, u.name, u.picture FROM posts as p INNER JOIN users as u ON p.user_id = u.id where p.id = ?");
$sth->execute(array(123));
$red = $sth->fetchAll();

How to query for both posts and post upvotes in MySQL?

I am attempting to model post upvotes and posts in MySQL. Currently I have an elements table for posts and a likes table for upvotes, structured as follows.
likes (id, elementID, googleID)
elements (id, googleID, title, body, type)
I have a URL route that will either return the most recent posts, or the posts with the most upvotes depending on a parameter. I want to query for a set of posts, each listing how many upvotes they have. The website won't display who upvoted, but the database should keep track of this to prevent multiple upvotes.
I tried to do something such as:
SELECT elements.id, elements.googleID, elements.title, likes.id, likes.elementID
FROM elements
INNER JOIN likes
ON elements.id=likes.elementID
This did not work well.
How would I get a set of posts, each showing how many upvotes they have when the upvotes are stored in a separate table?
I want to query for a set of posts, each listing how many upvotes
they have.
You can try this query. I used LEFT JOIN so you can still get the posts without likes.
SELECT E.id
, E.googleID
, E.title
, L.likeCount
FROM elements E
LEFT JOIN (
SELECT elementId
, COUNT(id) AS likeCount
FROM likes
GROUP BY elementId
) L ON L.elementId = E.id
Or (not pretty sure if this will run properly in MySQL)
SELECT E.id
, E.googleID
, E.title
, COUNT(L.id)
FROM elements E
LEFT JOIN likes L ON L.elementID = E.id
GROUP BY E.id
The website won't display who upvoted, but the database should keep
track of this to prevent multiple upvotes
You can create a UNIQUE CONSTRAINT in your LIKES table, for elementID and googleID columns. This will make sure that a googleID can only like one elementID. Otherwise, it will throw a unique constraint violation.
With that, when a user is upvoting a post, you can check in the database first if the user has already an existing record in the LIKES table before inserting one.

Complex SQL query, checking column values in multiple tables

I have a pretty huge SQL query to check for notifications, and I have several different types of notifications in the table, IE: posts, likes, comments, photoComments, photoLikes, videoLikes, etc. (Always adding more to it) And I have come into a problem, I'm not really sure how to best do this anymore. Thus far the way I have done it is working perfectly, and really quite easy to add to, however this one notification Type I have to check more than just one other table, I have to check two others and I haven't been able to get it to work.
So here it is: (This is only one part of my huge query, the only relevant part really)
n.uniqueID = ANY (
SELECT photos.id
FROM photos INNER JOIN posts ON (photos.id=posts.post)
WHERE photos.state=0
AND posts.state=0
AND posts.id = ANY (
SELECT likes.postID FROM likes
INNER JOIN posts ON (posts.id=likes.postID)
WHERE likes.state=0 AND posts.state=0
)
)
So basically all I really need to do is check the state columns in each table because that says whether or not it is deleted or not (if it's not 0 then it's deleted and shouldn't be returned)
So it would be like:
IF photos.state=0 AND posts.state=0 AND likes.state=0 return it.
n.uniqueID, posts.post, and photo.id will all be the same
value.
posts.id and likes.postID will also be the same value.
My issue is that it doesn't seem to be checking the likes.state, I don't think.
I think you just want to join the three tables together in a single query:
n.uniqueID = ANY (
SELECT photos.id
FROM photos INNER JOIN
posts
ON photos.id=posts.post inner join
likes
on posts.id = likes.postId
WHERE photos.state=0 and
posts.state=0 and
likes.state = 0
)
Your logic is not to return when there is a like or post with the state of 0. It seems to be that all the likes and posts have a state of zero. For this, do an aggregation with a having clause:
n.uniqueID = ANY (
SELECT photos.id
FROM photos INNER JOIN
posts
ON photos.id=posts.post inner join
likes
on posts.id = likes.postId
where photos.state = 0
group by photos.id
having MAX(posts.state) = 0 and MAX(likes.state) = 0

MySQL Query -- based on user and business ID's

I am working on a project right now and am rather stumped with a specific sql query I (need) to execute. Let me start off by showing the DB structure I need to pull from.
--posts_table--
ID
post_title
post_text
bus_id
This next table is what is screwing with me. The only way data related to the logged in user is in here is if they have "liked" a specific post -- otherwise there is no data related to that user in this table. Now there could be plenty of data related to a particular post, just generated from other users.
--likes_table--
ID
user_id
post_id
like
What I need this to do is grab all the posts from the post_table above where a specific business id is specified. From there, I need it to grab the "like" column in the likes_table if there is data in there related to the logged in user. If there is no data there, just leave that field null in the query. Below is a query I wrote that works until there is other "like" data in the like_table from other users.
SELECT posts.id, posts.post_text, posts.post_title, likes.post_id, likes.like
FROM posts LEFT JOIN likes ON posts.id = likes.post_id WHERE
posts.bus_id = 1 AND likes.user_id IS NULL OR likes.user_id = 1;
This works up until data has been entered in the table about a specific post being liked by a different user before that user has done anything with that post, whether they like or dislike it. I am not sure if this specific type of query is even possible, any help would be much appreciated.
Edit:
After looking at it again -- I got it, finally. I just needed to add one more AND. Below is the proper query I was looking for.
SELECT posts.id, posts.post_text, posts.post_title, likes.post_id, likes.like
FROM posts LEFT JOIN likes ON posts.id = likes.post_id AND posts.user_id = 1 WHERE
posts.bus_id = 1 AND likes.user_id IS NULL OR likes.user_id = 1;
Ahh, I think I get you -- is it that if a particular post hasn't been commented on by user_id number 1 at all, the row for that doesn't show up at all?
In that case, put your l.user_id=1 into the JOIN condition instead of the WHERE condition --- this will put a NULL in if user_id 1 hasn't liked or disliked a particular post.
SELECT p.id, p.post_text, p.post_title, l.post_id, l.likes
FROM posts p
LEFT JOIN likes l ON p.id = l.post_id AND l.user_id=1
WHERE p.bus_id = 1
The l.user_id IS NULL OR l.user_id=1 has been incorporated into the LEFT JOIN -- it doesn't make rows for the other user_ids.

Making a user profile activity feed

I need to build an activity feed to go on each users profile page showing what they have been doing on the site.
There is three tables: comments, ratings, users
I want the feed to include the comments and ratings that the user has posted.
in the comments and ratings table it stores the user id of the user who posted it, not the username, so in for each item in the news feed it needs to select from the users table where the user id is the same to retrieve the username.
All the entries in the feed should be ordered by date.
Here is what ive got even though i know it is not correct because it is trying to match both with the same row in the users table.
SELECT comments.date, comments.url AS comment_url, comments.user_id, ratings.date, ratings.url AS rating_url, ratings.user_id, users.id, users.username
FROM comments, ratings, users
WHERE comments.user_id=%s
AND comments.user_id=users.id
AND ratings.user_id=%s
AND ratings.user_id=users.id
ORDER BY ratings.date, comments.date DESC
JOIN. It seems you know that, but here's how:
SELECT * FROM comments LEFT JOIN users ON comments.user_id = users.id
Thus, as far as I can tell, you're trying to order two separate things at the same time. The closest I think I can come up with would be something like:
(SELECT comments.date AS date, users.username AS name, comments.url AS url CONCAT('Something happened: ',comments.url) AS text
FROM comments LEFT JOIN users ON comments.user_id = users.id
WHERE users.id = %s)
UNION
(SELECT ratings.date AS date, users.username AS name, ratings.url AS url CONCAT('Something happened: ',ratings.url) AS text
FROM comments LEFT JOIN users ON comments.user_id = users.id
WHERE users.id = %s)
ORDER BY date DESC LIMIT 0,10
Note that the columns of both parts of the union match up. I'm pretty sure that that is required for something like this to work. That's why I have that CONCAT statement, which lets you build a string that works differently between ratings and comments.