Okay, so I want to have a news feed on my website. I have 3 tables named Users, Follow, and Posts. Basic user data goes into the Users table, who is following who is stored in the Follow table, and whatever the user posts goes into Posts. Now, I know how to select every post from a database table and limit it using the WHERE clause. But how would I write my query to select all all of the posts from only user's they are following, and display them by DESC date? Thanks.
Here's a general layout for you, make three tables like you mentioned, I've outlined below just as an example
[TABLES]
users
followers
posts
In the users table you should have at least columns like userid (auto incremented value / primary key).
The followers table should have something like userid which would match to the users table userid, a followid column which would also have the id # for the follower from the users table.
Then for your posts table you would want to have userid too so when each post is made it would have the id from users table.
Then you would need to do something like:
SELECT p.*
FROM posts AS p
WHERE p.userid IN (SELECT followid FROM followers WHERE userid = ###)
ORDER BY p.date DESC
Now it really depends on how you are getting the users id to figure this out. If your passing the users id using a session after they logged in similar to something like Facebook, then you could change userid = ### to something like userid = ".$_SESSION['userid']." But again it really depends on how you pass the users id but the above should at least get you somewhat started.
Make sure to put indexes on the userid, followid columns so that when the table becomes larger it will do the joins quickly.
An alternative to #Shane's answer is to use the JOIN operator:
'SELECT p.* // I prefer to name all the fields, but for brevity's sake I'll use the shorthand
FROM Posts AS p
INNER JOIN Follow AS f ON p.userid = f.followid
WHERE f.userid = '.$selectedUserID.'
ORDER BY p.date DESC;'
For an inputed User ID ($selectedUserID), it will find all User ID's of the people they follow (matching follow ID to user ID on the Follow x-ref table) and then find their respective posts from the Post table in descending order by date. It will return empty if they do not follow anyone or the people they follow have no posts.
I also hope I do not need to remind you to sanitize your input to the database and escape your output to the web.
Is this what you're looking for?
Related
I`m working on a small website where people can follow each other. There are newsfeed on the site where users can see updates from other users that they follow. The problem is that I can see only posts from other users and not my posts. I want the current user to be able to see his posts too Ordered within the other users posts. Something like Facebook Wall.
I have tried tons of differend queries and php, but I get only other users post or when i manage to pull out my posts too there are dublicate post for every user that follows me.
I have 3 tables 'members', 'Post' and 'follow'. The members table hold UserID, Name and Last Name. Post table holds the UserID(FromID in the table) Indexed to members UserID and the post from the user. In the follow table there are 3 columns FollowID, Followed and Follower both Followed and Follower are index to members UserID.
At the moment I use that query:
$query= "SELECT Post.*, members.*, follow.* FROM Post
INNER JOIN members ON Post.FromID=members.UserID
LEFT JOIN follow ON members.UserID=follow.Followed
WHERE Post.FromID='$user' OR follow.FollowerID='$user'
ORDER BY Post.date DESC, Post.time DESC";
$user is the UserID of the current logged in user.
That query returns all the posts that I want but the problem is that my post are show /n times for each user that follows me.
I really would appreciate the kindness to the one that give me some directions what i do wrong. Thank you
The problem is with your $user. Currently what is happening is that you have an OR condition in where clause. And you are trying to pull either your data or ur followers data.
My solution for you would be to remove $user from the query you have. So you will have list of followers data only. Have a different query for your posts and then while displaying sort them by datetime Timestamp so you have your posts with other followers too.
To have your posts and folloeers posts in one query.
Use union. Like :
(Query of your posts ORDER BY date)
UNION
(Query of followers posts ORDER BY date);
Also check UNION usage in w3schools.
Hope this helps
I think this query might be easier to understand:
$query = "SELECT * FROM Post,members,follow
WHERE
Post.FromID=members.UserID
AND
members.UserID=follow.Followed
AND ( Post.FromID='$user' OR follow.FollowerID='$user')
ORDER BY Post.date DESC, Post.time DESC";
Let's imagine I have a databases with two tables, Users and Posts. The first table contains a row for each user, the second table a row for each post that users have written. If I want to display a post count on the users' profiles, which of these two strategies work the best:
Every time a user creates a post I UPDATE the Users table, +1 a field PostCount;
When someone visits the profile I simply run a select statement to get a count of post, for example SELECT COUNT(post_id) FROM Posts WHERE id_user = 100;
In the first case I have to UPDATE a table very often, which it could be bad as I believe a table gets locked when doing the update; in the second case I have to run a count every time the user visits a profile. Which poison is the less bitter? Is there any other way?
I would say that it depends on how many times you will display PostCount, especially for a huge amount of Users. If you are going to display it for 1000+ users on a page that will be called a lot of times, then the first solution should be the best. But you need to do transactions to be sure both tables Posts and Users are updated when adding a new post.
Otherwise, the second solution should be enough, but you should use LEFT OUTER JOIN so that you would get both information from Users and Posts table in only one query. Eg:
SELECT *
FROM Users u
LEFT OUTER JOIN (
SELECT user_id , COUNT(*) AS posts_count
FROM Posts
GROUP BY user_id
) p ON p.user_id = u.id
WHERE u.id = :searched_id
(And anyway you should use a Cache system so that you don't have to do the same SQL query for a same page if shown to several users.)
Consider this mysql tables structure (useful to store private/group chat messages):
USERS
user_id
username
password
GROUPS (= DISCUSSIONS / TOPICS)
group_id
name
GROUPS_MEMBERS (= MEMBERS OF A SPECIFIC DISCUSSION / TOPIC)
group_id
user_id
MESSAGES
message_id
timestamp
from_user_id
destination_type (enum - group, user)
destination_id
Can you please help me with the query to retrieve the list of the 5 more recent dicussions (either private or group) in which a specific user has been a active?
Important:
I don't have actual code since I'm just deciding how to structure the database tables. The table structure presented above it's pretty self-explanatory (destination_id is a reference to group_id, and group members are all the users that will receive a message. Finally, all messages sent between the users of a specific group make a discussion or topic).
Here is what I want to do (it's very easy... don't over-think it... it's like any chat/messaging system like Facebook or Gmail etc).
When a user logs in and opens the chat he will of course see all the latest discussion which he is/has been a part of. In a chronological DESC order.
So I need to write the query to retrieve the latest 5 GROUP_IDs (= discussions) in chronological DESC order. But only the discussions which the logged-in user is a part of.(Of course I have the id of the logged-in user.. for example 16)
P.s. I didn't build this table structure myself but it seems logic; the only problem is the one presented above.
Here's my suggestion. You can get different records by using DISTINCT and get only five records by using LIMIT. You can replace logged_in_user_id with the login id.
SELECT DISTINCT GROUPS.group_id FROM USERS
JOIN GROUP_MEMBERS ON USERS.user_id = GROUP_MEMBERS.user_id
JOIN GROUPS ON GROUPS.group_id = GROUP_MEMBERS.group_id
JOIN MESSAGES ON destination_type = 'group' AND destination_id = GROUPS.group_id
WHERE USERS.user_id = logged_in_user_id
ORDER BY timestamp DESC
LIMIT 5;
#Igor Carmagna:
I have gone through your question and according to that i think you are required list the top 5 messages which have been left by the end users right ?. So for that please please follow below given steps.
1) First and for most thing you are required to do is that Join.
2) In this step you are required to use max() function which will give you list of the users on the base of messages received. Now, according to your question you are required to have only top 5 records so you are bound use (max-5) function this will given top 5 records
Hope this will make you day !!
Cheers :) :P
Let me set up the situation first.
I have a "users" table with X fields, the fields dont really matter for my question except for "visibility". Visibility is a tinyint and the values mean the following (0 = visible to all, 1 = visible to friends only, and 2 = invisible).
I also have a friends table (id, user_id, target_user_id). user_id is friends with target_user_id. Easy enough so far right?
Here is where it gets sticky. Im writing a PHP API and my class method looks kinda like this:
public function getUsers($requester, $page, $num) {}
the $requester is the user id of the person requesting the users
the $page is the pagination page number
the $num is the number of items per page
What I want to do in SQL is get $num users from the users table if their visibility field is = 0 or 1. If the visibility flag is 1 however, I need to make sure the user id and the $requester are friends in the friends table and only return that user if they are friends.
I thought about using PHP to filter the visibility after I get my results back but the pagination (limit) will be screwed up if I ask for 5 records for example and one or more user has visibility set to 1 and are not friends with the requester. This pretty much has to be done entirely thru sql.
Possible??
Try creating a temp table 'temp' with same structure as users.
select * into temp From users where visibility=0 or visibility=1;
Select * from temp, friends where (temp.visibility=0) or (temp.user_id = friends.target_user_id);
Don't forget to empty the temp table.
I haven't tried the second query yest, let me know what output you got.
select * from users, friends where (users.visibility=0) or (users.visibility=1 and users.user_id = friends.target_user_id);
I think you can use LEFT JOIN for this.. something like
"SELECT *
FROM users t1
LEFT JOIN friends t2 ON t2.user_id=t1.id AND t1.visibility=1
INNER JOIN user t3 ON t3.id=t2.target_user_id
WHERE t1.visibility=0 OR t1.visibility=1
LIMIT ".($page*$num).",".$num
I'm trying to get a users position between the users friends, but I don't have any idea of how I can do this...
I have two tables.
Table 1: friends (where all the users friends are listed)
Table 2: users (where all the users are listed)
I want the query to check the users position between his friends.
So if I, for example have ID 1 (with 100 credits) and a friend with ID 2 (with 21 credits), the query would list my position as 1.
You don't really provide much information on your table layout, so it's going to be impossible for me to provide a very specific example. I'm also afraid I don't really understand your question, but I'll give it a shot...
First, I'll assume your users table has at least these columns:
id (PK)
credits
And that the friends table has these columns:
user (FK to users.id)
friend (FK to users.id)
Now, if I understand your question, you want to rank all of a user's friends, based on how many credits they have, so:
SELECT u.id,u.credits
FROM friends AS f
JOIN users AS us ON f.friend = u.id
WHERE f.user = 1
ORDER BY u.credits DESC;
in order to get the position I would recommend using PHP for this and not try to put it all in one query. So get a sorted list like Flimzy described and get the position by using an array function like array_search.