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

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.

Related

is there any way to count by values in a column and find a specific value from another column in mysql?

I am trying to combine two tables,
one(Post Table) is for posts and the other one(Like Table) is for likes that people put on the posts.
then I want to render 10 posts with the number of likes that the posts got and I want to mark on each post if the user put a like on it before or not.
I managed to select counts group by post_id on the Like Table so I know how many likes each post has
but I can't think of any way to do that and make the user see if the user put a like on the posts before at the same time.
so what I came up with is:
somehow count the user's id(from Like Table) and from the result of the group by post_id and join two results
just use two mysql queries
I don't know how to do any of them. I would like to know about more detailed way to do those if they're possible to do or other way to solve the problem.
Something like this is probably the simplest way to do it:
SELECT *
FROM Posts p
LEFT JOIN (
SELECT postID, COUNT(*) likes, COUNT(CASE WHEN userID = 123 THEN 1 ELSE 0 END) usersLikes
FROM Likes
GROUP BY postID
) l ON l.postID = p.id

Select all posts that user hasn't responded to?

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

Retrieving data from 3 Mysql tables

Suppose I have 3 different tables relationships as following
1st is tbl_users(id,gender,name)
2nd is tbl_feeds(id,user_id,feed_value)
3rd is tbl_favs(id,user_id,feed_id)
where id is primary key for every table.
Now suppose I want to get data where those feeds should come which is uploaded by Gender=Male users with one field in every row that should say either the user who is calling this query marked that particular feed as favourite or not.
So final data of result should be like following :
where lets say the person who is calling this query have user_id=2 then is_favourite column should contain 1 if that user marked favourite that particular feed otherwise is_favourite should contain 0.
user_id feed_id feed_value is_favourite gender
1 2 xyz 1 M
2 3 abc 0 M
3 4 mno 0 M
I hope you getting my question , I m able to get feeds as per gender but problem is I m facing problem to get is_favourite flag as per particular user for every feed entry.
I hope some one have these problem before and I can get help from those for sure.
I would be so thankful if some one can resolve my this issue.
Thanks
Something like this should work:
SELECT
u.id AS user_id.
fe.id AS feed_id,
fe.feed_value,
IFNULL(fa.is_favourite, 0),
u.gender
FROM
tbl_users u
JOIN
tbl_feeds fe ON (fe.user_id = u.id)
LEFT JOIN
tbl_favs fa ON (
fa.user_id = u.id
AND
fa.feed_id = fe.id
)
In order to link your tables, you need to find the most common link between them all. This link is user_id. You'll want to create a relationship between all tables with JOIN in order to make sure each and every user has data.
Now I don't know if you're planning on making sure all tables have data with the user_id. But I would use INNER JOIN as it will ONLY show records of that user_id without nulls. If the other tables could POSSIBLY (Not always guaranteed) you should use a LEFT JOIN based on the tables that is it possible with.
Here is an SQLFiddle as an example. However, I recommend you name your ID fields as appropriate to your table's name so that way, there is no confusion!
To get your isFavorite I would use a subquery in order to validate and verify if the user has it selected as a favorite.
SELECT
u.userid,
u.gender,
f.feedsid,
f.feedvalue,
(
SELECT
COUNT(*)
FROM
tbl_favs a
WHERE
a.userid = u.userid AND
a.feedsid = f.feedsid
) as isFavorite
FROM
tbl_users u
INNER JOIN
tbl_feeds f
ON
u.userid = f.userid
~~~~EDIT 1~~~~
In response to your comment, I have updated the SQLFiddle and the query. I don't believe you really need a join now based on the information given. If you were to do a join you would get unexpected results since you would be trying to make a common link between two tables that you do not want. Instead you'll want to just combine the tables together and do a subquery to determine from the favs if it is a favorite of the user's.
SQLFiddle:
SELECT
u.userid,
f.feedsid,
u.name,
u.gender,
f.feedvalue,
(
SELECT
COUNT(*)
FROM
tbl_favs a
WHERE
a.userid = u.userid AND
a.feedsid = f.feedsid
) as isFavorite
FROM
tbl_users u,
tbl_feeds f
ORDER BY
u.userid,
f.feedsid

Advise for best query performance (MySQL)

I'm looking for the best MySQL query for that situation:
I'm listing 10 last posts of a member.
table for posts:
post_id | uid | title | content | date
The member have the possibility to subscribe to other member posts, so that posts are listed in the same list (sorted by date - same table)
So it's ok to select last posts of userid X and userid Y
But I'd like to allow members to diable display of some posts (the ones he doesn't want to be displayed).
My problem is: how can I make that as simple as possible for MySQL?... I thought about a second table where I put the post ids that the user doesn't want:
table postdenied
uid | post_id
Then make a select like:
select * from posts as p where not exists (select 1 from postdenied as d where d.post_id = p.post_id and d.uid = p.uid) order by date DESC limit 10
I'm right?
Or is there something better?
Thanks
If I understand correctly, the posts.uid column stores the ID of the poster. And the postdenied.uid stores the ID of the user that doesn't want to see a certain post.
If the above assumptions are correct, then your query is fine, except that you should not join on the uid columns, only on the post_id ones. And you should have a parameter or constant the userID (noted as #X in the code below) of the user that you want to show all the posts - except those he has "denied":
select p.*
from posts as p
where not exists
(select 1
from postdenied as d
where d.post_id = p.post_id
and d.uid = #X -- #X is the userID of the specific user
)
order by date DESC
limit 10 ;
Another approach to implementing this would be with a LEFT JOIN clause.
SELECT * FROM posts AS p
LEFT JOIN postdenied as d ON d.post_id = p.post_id and d.uid = p.uid
WHERE d.uid IS NULL
ORDER BY date DESC
LIMIT 10
It's unclear to me whether this would be more amenable to the query optimizer. If you have a large amount of data, it may be worth testing both queries and seeing if one is more performant than the other.
See http://sqlfiddle.com/#!2/be7e3/1
Appreciation to ypercube and Lamak for their feedback on my original answer

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