I am working on a project that requires getting posts from my database. I am trying to get the posts that are posted by the user and other users unless they are private.
My SQL query is
SELECT . . .,COUNT(F.user_id) AS is_following FROM posts AS P INNER JOIN users AS U ON U.id = P.user_id LEFT JOIN followers AS F ON F.user_id = :userid AND F.following_id = U.id WHERE *If matches search* AND U.private = 0 OR U.id = :userid OR is_following = 1 ORDER BY. . .
I am selecting where the user is following the posters and counting it if 0 it means they are not following and 1 would mean 1 result, therefore, following them. Also I am checking if private is 0 meaning the account is public.
The problem is while I have the is_following = 1 it returns no results if I remove it though it does return results but not all.
Tables:
users: id|username|private|...
followers: userid|followingid
posts: id|userid|body
Content:
users:
user1|test1|1 (This is the user running the request)
user2|test2|1
user3|test3|1
followers:
user1|user2 (User searching follows test2)
posts:
post1|user1|HelloWorld
post2|user2|Hello_World
post3|user3|Hello-World
The expected outcome is to return post1 and post2 but not post3 since user3 is private (private is set to true/1) and user1 does no follow test3, but it should display user2's post since user1 follows user2
If I understand correct.
There are two kinds of groups
private is 0 meaning the account is public
private is 1 need to find the following User on followers table.
A simple way you can make two query one is for private is 0 , another is for private is 1 ,then use UNION ALL combine those.
SELECT * FROM
(
SELECT p.*
FROM users as u
INNER JOIN posts AS P ON p.userid = u.id
WHERE u.private = 0
UNION ALL
SELECT p.*
FROM users as u
INNER JOIN posts AS P ON p.userid = u.id
RIGHT JOIN followers AS F ON F.followingid = u.id
WHERE u.private = 1 AND f.userid = :userid
)t
Or use exists to check it
SELECT p.*
FROM users as u
INNER JOIN posts AS P ON p.userid = u.id
WHERE u.private = 0 OR exists
(
SELECT 1
FROM followers AS F LEFT JOIN users ON F.followingid = users.id
WHERE u.id = users.id
and users.private
and f.userid = :userid
)
sqlfiddle:http://sqlfiddle.com/#!9/50ef05/1
EDIT
if you want to get the user is or isn't is_following,you could follow like this.
then you could find which user have been is_following on outer where clause .
SELECT * FROM
(
SELECT p.*,0 as 'is_following'
FROM users as u
INNER JOIN posts AS P ON p.userid = u.id
WHERE u.private = 0
UNION ALL
SELECT p.*,1
FROM users as u
INNER JOIN posts AS P ON p.userid = u.id
RIGHT JOIN followers AS F ON F.followingid = u.id
WHERE u.private = 1 AND f.userid = 'user1'
)t
/*where is_following = 1*/
sqlfiddle:http://sqlfiddle.com/#!9/b7f6c/10
The reason it returns no results when you have the is_following condition is that you are trying to use an alias in a WHERE clause which is not permitted by MySQL. Replace is_following with COUNT(F.user_id) and it should work.
Related
I want to display all users data, who User 'A' is following. And then further check if User 'B' is also following some users of User 'A'.
I managed to get al users data, who User 'A' is following. But don't understand how to query for the second condition.
Here is my Fiddle link with an example: https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=29a7d1e29f794a8f18a89fe45c06eaa9
You can try to let your User 'B' in a subquery then do OUTER JOIN
SELECT u.*,
IF(friend_id IS NULL,0,1) amIfollowing
FROM users u
LEFT JOIN (
Select friend_id
from friends
where user_id = 5
) f ON f.friend_id = u.id
WHERE u.id IN (SELECT f.friend_id
FROM friends f
WHERE f.user_id = 1)
ORDER BY u.id
sqlfiddle
If I understand correctly you can try to use only one subquery for friends and then use the condition aggregate function to get the result.
SELECT u.id,
u.image_width,
MAX(CASE WHEN f.user_id = 5 THEN 1 ELSE 0 END) amIfollowing
FROM users u
JOIN (
Select friend_id,user_id
from friends
where user_id IN (1,5)
) f ON f.friend_id = u.id
GROUP BY u.id,
u.image_width
ORDER BY u.id
You could use exists here to check if the corresponding IDs exist:
SELECT *,
case when exists (
select * from friends f
where f.friend_id = u.id and f.user_id = 5
) then 1 else 0 end amIfollowing
FROM users u
WHERE u.id IN (SELECT f.friend_id
FROM friends f
WHERE f.user_id = 1);
Example Fiddle
Looks like a JOIN will do, with distinct
SELECT distinct u.*, (f2.user_Id is not null) amIfollowing
FROM users u
JOIN friends f ON u.id = f.friend_id
LEFT JOIN friends f2 on f2.friend_id = f.friend_id and f2.user_id = 5
WHERE f.user_id = 1
ORDER BY u.id
I'm working on a project where I need to check if the user liked the post and then use COUNT() on it, if it gives 0 they haven't if it says 1 they have liked it
I tried using this query
SELECT P.id AS id
, U.username AS username
, P.body AS body
, P.timestamp AS timestamp
, COUNT(L.user_id) AS likes
, COUNT(LD.post_id) AS liked
FROM posts AS P
LEFT JOIN users AS U ON U.id = P.user_id
LEFT JOIN followers AS F ON F.user_id = 'user1'
LEFT JOIN likes AS L ON L.post_id = P.id
LEFT JOIN likes AS LD ON LD.post_id = P.id
AND LD.user_id = 'user1'
WHERE F.following_id = P.user_id
OR P.user_id = 'user1'
GROUP BY P.id
My entrys in my likes table are
UserId|PostId|timestamp
user1 |post1 |time
user2 |post1 |time
My problem is it keeps giving a 2 for the count of LD which shouldn't be possible
*Note: In my code I use :user through PDO I don't actually type the id like that
Edit:
$sql = "SELECT P.id AS id, P.user_id AS userid, U.username AS username, U.name AS name, U.verified AS verified, P.body AS body, P.data AS data, P.timestamp AS timestamp, P.type AS type, P.users AS users, COUNT(L.user_id) AS likes, COUNT(DISTINCT LD.post_id) AS liked FROM posts AS P LEFT JOIN users AS U ON U.id = P.user_id LEFT JOIN followers AS F ON F.user_id = :userid LEFT JOIN likes AS L ON L.post_id = P.id LEFT JOIN likes AS LD ON LD.post_id = P.id AND LD.user_id = :userid WHERE F.following_id = P.user_id OR P.user_id = :userid GROUP BY P.id";
$results = DB::query($sql, array(':userid' => $user_id));
I then loop through the results and format them into json
Can you try adding a DISTINCT keyword on the COUNT function for liked column?
COUNT(DISTINCT LD.post_id) AS liked
Most likely the joins are causing the likes table to be duplicated. Thus, we'll only count the unique posts (by post_id) using DISTINCT.
Table users:
id----email
1-----s#s.com
2-----p#p.com
Table user_buddies
id-----user_id----buddy_id----status enum('accepted','pending')
1------1----------2-----------pending
Suppose I am querying with respect to user 2 then I want to get user 2 email. If I am querying with respect to user 1 then I want to get user 1 email.
The below query is always returning empty rows.
SELECT
users.email,
ub1.*, ub2.*
FROM
users
JOIN user_buddies ub1 ON users.id = ub1.user_id
JOIN user_buddies ub2 ON users.id = ub2.buddy_id
WHERE
users.id = 1;
Can anyone please help me in this?
Thank you.
Expected result:
email-----user_id-----buddy_id-----status
s#s.com --1-----------2------------pending (If queryed on user 2)
p#p.com---1-----------2------------pending (If queried on user 1)
Context:
When user1 sends request to user2 only one row is added to the user_buddies table with status=pending. So, both for user1 and user2 buddy list is created using same row. So if queried against user2 email needed is user2's.
You may check the following query:
SELECT
users.email,
ub1.user_id,
ub1.buddy_id,
ub1.`status`
FROM
users
JOIN user_buddies ub1 ON users.id = ub1.user_id OR users.id = ub1.buddy_id
WHERE users.id = 2;
SQL FIDDLE DEMO
Result:
email user_id buddy_id status
p#p.com 1 2 pending (if queried on users.id = 2)
s#s.com 1 2 pending (if queried on users.id = 1)
EDIT:
SELECT
(
SELECT
u.email
FROM users u
WHERE u.id =
IF (
users.id = ub1.user_id,
ub1.buddy_id,
ub1.user_id
)
) AS buddyEmail,
ub1.user_id,
ub1.buddy_id,
ub1.`status`
FROM
users
INNER JOIN user_buddies ub1 ON users.id = ub1.user_id
OR users.id = ub1.buddy_id
WHERE users.id = 2;
Check this fiddle of this new query
SELECT 'Userid' querysource, u.id, u.email, ub.*, u1.EMAIL AS Buddyemail
FROM #users u
JOIN #user_buddies ub ON u.id = ub.user_id
JOIN #users u1 ON u1.id = ub.BUDDY_ID
WHERE u.id = 1
UNION
SELECT 'Buddyidid', u.id, u.email, ub.*, u1.email AS Buddyemail
FROM #users u
JOIN #user_buddies ub ON u.id = ub.buddy_id
JOIN #users u1 ON u1.id = ub.user_ID
WHERE u.id = 1
I have 2 tables:
posts: userid, lastuserid
users: id, name
I need to join posts.userid = users.id and posts.lastuserid = users.id to get username and lastusername.
My query did as below:
SELECT posts. * , users.name, vUsers.name
FROM posts
INNER JOIN users ON users.id = posts.userid
INNER JOIN Users ON vUsers.id = posts.lastuserid
Is there any other (better) way to do this?
Your query is probably correct. I would encourage you to use table aliases that are abbreviations for the things you are looking for:
SELECT p. * , u.name as username, l.name as lastusername
FROM posts p INNER JOIN
users u
ON u.id = p.userid INNER JOIN
users l
ON l.id = p.lastuserid;
Your query has something called vUsers, which is not defined.
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.