Mysql Query to fetch data of shared posts - php

DB Schema is given below. how can i fetch posts plus shared posts of users like Facebook. in Facebook wall the we can see original posts and the posts user shared. how can i actively get the posts. records could be in millions.
i have tried using joining two tables but i am unable to identify the shared posts.
SELECT *
FROM
post_shares
INNER JOIN posts
ON (post_shares.post_id = posts.id);

select id, description from post where user_id = 'xyz'
union
select id, description from post p, post_shares ps where p.id = ps.post_id and ps.user_id = 'xyz'
Top part of the query will give you posts for user 'xyz' and second part will give you posts that the user shared.

Related

Show posts from users that I follow, but show my posts too

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";

php, MySql subquery from two tables

I'm trying to build a MySql query to produce results based on following:
Table Permissions
user_id blog_id
=========================
1 1
1 2
1 3
2 2
3 1
Table Blog
id name
=========================
1 First Blog
2 Second Blog
3 Third Blog
4 Fourth Blog
I need to select all the records from Blog table and display it based on logged in user id like:
$user_id = $_SESSION['user_id];
Table Permissions contains access for each user allowed to view results from blog table.
So something like:
"SELECT * FROM Blog WHERE id IN()"
but I'm not sure how to access permission table to use it in IN().
So for example if user with id 1 is logged in, this user should be able to see Blogs with matching id's 1,2 and 3.
You can use either a join, or an in() subquery.
select b.* from blogs b
inner join permissions p
on b.id=p.blog_id
where p.user_id=...
Try this:
SELECT * FROM Blog INNER JOIN Permissions ON Permissions.blog_id = Blog.id
This show all users.
Working code here: http://sqlfiddle.com/#!9/aa3e9/14
You can use:
SELECT * FROM Blog INNER JOIN Permissions ON Permissions.blog_id = Blog.id
WHERE Permissions.user_id = 'user_id number'
To get a specific user.

Mysql join query for showing friends posts with viewstatus!=public

I have three table tbl_user, tbl_posts, tbl_friends
tbl_user stores all the user datas.
tbl_friends stores which user are friends with other.
tbl_posts, where the users posts are stored. userid is the field where all the users id are stored. p_viewstatus field stores the view status of the posts. if the view status of the my friends posts is only by me then that posts should not shown to other users
If sam have a post with id=40 in tbl_posts. The p_viewstatus of the post is only by me then that post must only be visible to sam only.
If sam have another post with id=41 and p_viewstatus!='only by me' this post must visible to all users who are sam's friend
Tried the following query but don't know how to relate the p_viewstatus
Note: I want to fetch all of my posts and my friends posts from **tbl_posts except the p_viewstatus of my friends posts no equal to 'only by me'**
SELECT * FROM `tbl_posts` as p,`tbl_friends` as f WHERE p.`userid`=f.`userid` and p.`userid`=23
Thanks in advance.
BELOW SCREENSHOT SHOWS THE TABLE CONTENTS AFTER JOIN QUERY.
Here's how your query should look like:
SELECT * FROM `tbl_posts` as p
WHERE p.`userid`=23 OR (p.`userid` IN (SELECT `friendsid` `FROM tblfriends` WHERE `userid`=23)
AND p.`p_viewstatus`<>'only by me')
First you select the data from the table you need. After that you filter it with the user id and the ids of the friends of the user and you also tell it that you only want the posts that are not viewable only by me.

User specified content sharing like G+

I'm building a site that requires sharing with either group(s) or individual user(s). I know for a fact that google does not use mysql, but i was wondering how i could replicate such feature on my site. On g+, one can:
Share a post with the "public" (everyone can see it).
Share a post with "all circles" (everyone in your circles can see it).
Share a post with both circles and individual users. E.g. post = "my first post" and is shared with family,friends, user 1(Joey tribbiani), user 2 (Ross geller) etc.
Conditions:
If a post is shared with a circle and a new user is added to the circle, then (s)he should be able to see all the previous posts shared with that circle.
If a user is removed from a circle. (s)he cannot see posts shared with that circle except posts (s)he has commented on.
Currently my database tables look like this.
Circle_category
Cat_id
Cat_name
user_id
Posts
post_id
user_id
post
is_public
all_circle
Post_to_circle
entry_id
post_id
cat_id
Post_to_user
entry_id
post_id
user_id
Post a user in family circle(which is in Circle_category with cat_id of 1 ) can see
They can see posts that are public.
They can see posts shared with all circles.
They can see posts shared with family circle.
They can see posts shared with them (Individual user).
SQL
SELECT p.* FROM posts p
JOIN Post_to_circle pc
ON p.post_id = pc.post_id
JOIN Post_to_user pu
ON p.post_id = pu.post_id
WHERE p.is_public = 1
OR all_circle = 1
OR pc.cat_id = $cat_id
OR pu.user_id = $user_id
Quetions:
Firstly, I've been able to get posts from case 1(see all public post), case 2 (Posts shared with all circles) but the other 2 cases do not work. I thought about it and saw that the main problem is that i specified the where clause to get posts where p.is_public = 1 which means it neglets rows where p.is_public = 0. How do i update the query so it shows posts covering all four cases and also covers the conditions we talked about at the beginning.
Secondly, is there a better way to structure my tables? i'm not sure i'm doing it the right way.
From a quick read trough, all i can say is:
you are using a join statement instead of a left join statement.
using join means:
keep all rows from the table used in from-clause that validate true for the condition specified in that join clause.
since you are using 2 statements, the first join throws away all the records that dont have the needed join, the second join throws away all the records that dont have the needed join in the second one, but it only uses records that matched the first join.
you should use left join instead. this keeps all rows from the first table. all rows that didnt have a match, get the values NULL for the columns specified in the joined table(s)
simple example:
users table:
user_id
name
user_posts
post_id
user_id
content
created
related queries:
select *
from users u
JOIN user_posts up on up.user_id = u.user_id and up.created > date_sub(curdate(), interval 1 day)
this will use all users and make match with each post that was created less then a day ago by that user.
if the user didnt have a post in the last day, he will NOT be in the resultset.
change this example to
select *
from users u
LEFT JOIN user_posts up on up.user_id = u.user_id and up.created > date_sub(curdate(), interval 1 day)
this will use all users and make a match with each post that was created less then a day ago by that user
if the user hasn't posted in the last day, he will STILL be in the resultset, but all the columns from the posts table will be NULL
the where filters all the rows you have left after the joins. (mysql will use where clauses before joining, if they can speed up the query).
altering your query:
make sure the clauses in where statement are wrapped between () for all the different cases. ALSO this is NOT the complete answer, as there is info missing (example user tables, circle relation tables, friend relations)
also the all_circles option confuses me, so it's missing from the query, but this should get you on the right track
SELECT p.* FROM posts p
left JOIN Post_to_circle pc
ON p.post_id = pc.post_id and /* define statement for valid circles for user you're trying to get the posts for */
left JOIN Post_to_user pu
ON p.post_id = pu.post_id and /* define statement for valid friends for user you're trying to get the posts for */
WHERE
/* 1 day old */
p.created > date_sub(curdate(), interval 1 day)
AND (
/* is public */
p.is_public = 1 OR
/* or to friends */
pu.id is not null OR
/* or to circles */
pc.id is not null
)
Also, i'm suspecting you'll need 2 subqueries, which is not the best thing to do, and my advise would be to find all correct ids for the friends, and all ids for the valid circles and then using an IN clause in each join statement (part thats in comment)

Using an array in an SQL query

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?

Categories