How to select all posts from database? - php

In database in table user I have three columns:
id
name
friends
In column friends are names of people who are friends with person whose name is stored in column name. Column friends looks like this:
friendname1,friendname2,friendname3,friendname4
Each of those friends have it's own row where name is equal to their name.
I also have another table called post where I have four columns:
id
name_posted
post
visible
What I would like now, is to select all posts from table post where name_posted is equal to name of the logged in user or any of his friends which are stored in column friends in table user.
Name of the logged in user is stored in variable $user.
For selecting only posts from logged in user I can use this:
$all_posts = mysqli_query($connect_db, "SELECT * FROM post WHERE name_posted='$user' AND visible='yes'");
but I don't know how to include to select also posts from his friends. Something like Facebook have, when you log in and you see your posts plus your friends posts. I don't know how they created that. Sorry for long post, I just wanted to give you detailed description.

For selecting data based on information across multiple tables I suggest reading up on MySQL Joins.

Maybe with two querys, first select friends something like this:
SELECT * FROM user WHERE name='$user'
You then have all his friends in string like this if I understood correctly :
friend1,friend2,friend3...
Explode $row['friends'] -> explode(',',$row['friends']); to get all friends names in array and then you can do another select in foreach loop to get all posts from friends and display it the way you like or you can even better do IN in query
select * from posts where name_posted IN ($row['friends'])
this is the other way, which would be longer
foreach($friendarray as $k=>$friend){
...
mysqli_query($connect_db,
"SELECT * from post where name_posted='$friend' AND visible='yes'");
...
}
and also the query you already have to get own posts. Don't forget to escape all values and stuff...
You could also join two tables but I cant write that query from my mind , would have to sit down and try it with real data but that would be ultimate solution for you.
Don't know if I hit it right but shout if you need help

You can do it in a single query with something like:
SELECT p.*
FROM user u
join post p
on (u.name = p.name or concat(',',u.friends,',') like concat('%,',p.name,',%')
AND p.visible='yes'
WHERE u.name='$user'
- but the performance is likely to be much poorer than if you had a properly normalised design for the relationship between users and their friends.

You should probably reconsider the design of your DB. From what you've described, you should have three tables: userinfo, friendship, posts.
That way, you can then do a quick union between all three tables to get what you're looking for in one query.

Let me talk about how I will solve that case if its required from me.
I will use the following tables
users - user_id, name, email and whatever I need
relations - relation_id, user_id, fiend_id -- this table will relate one user to other
posts - post_id, user_id, content, visible
Now basically we have everything needed.
For selecting all data from the currently logged user and all of his friend I will use the following query:
SELECT * FROM posts
WHERE Visible = 1
AND (
user_id IN (SELECT friend_id FROM relations WHERE user_id = 1)
OR
user_id = 1)
What I do here, I use nested queries to accomplish that.
The interesting part here is the nested query - which basically return "array" with the ids of my friends. MySQL IN function check the user_id against that "array" After that in the main parentheses I add OR user_id = 1 which is the my user_id.
In that way I should have the content which I want to use to my feed.
However this code I away from fast and optimized but it's good example how to do that.

Related

Linking two rows from same table MYSQL

As an example, let's say I want users to be friends on the website.
Say, user_id 1 and user_id 2 become friend, I add a row to my table friends:
table friends (user_id1 INT, user_id2 INT), the problem with this table is that I have to query each column to get my results.
Rows may be:
user_id1 user_id2
1 2
2 3
So to get friends of user with id 2, I need to query both columns (which make some not so practical queries), is there a better way to do this?
ie:
$u_id = 2;
SELECT * FROM friends WHERE (user_id1 = $u_id OR user_id2 = $u_id)
I would go for the less space efficient method of adding two rows one linking person A to person B and the second linking person B to person A. Then a single query on a single column will retrieve all friends.
This set up can also be used where "friends" have different privileges or levels of friendship. So person A can give B more access to their stuff than B gives to A.
You could try a different approach, storing all friends of a person inside a field friends in the table and storing everything as a json object.
This way you'd have all one person's friends in a single query and you could get tehir profile with a simple foreach query.
I've been using this for several many-to-many logics and it works flawlessly without the aid of a link table.
I think I'd prefer a UNION, something like:
SELECT user, friend FROM (
SELECT user_id1 AS user, user_id2 AS friend FROM friends
UNION
SELECT user_id2 as user, user_id1 AS friend FROM friends
) u
WHERE u.user = $u_id
(with appropriate caveats about using prepared statements instead of bare variables of course)

mysql how to show some rows of table depending on one field and depending on one field in other table?

I have a script where members login and read posts by catagory that I have in
Table called posts, then they click a button and an entry is inserted into Table
called postsread collecting the postname, their memberid, and the date showing
that it had been read by them. What I am looking for is a query that will
display to them only the posts that they have not already read.
**Tables** **Fields**
posts id, name, date, from, topic, info, cat
postsread id, postname, memberid, date
users id, memberid, pass, fname, lname, email
Sessions is already holding their $_SESSION['memberid'], but am unsure of how
to query between the two tables to get what I'm looking for.
It would be like: Show all posts in Posts except those in Postsread with the members
memberid next to the corresponding postname.
I am using php version 5.3, and mysql 5.0.96.
I am using the following to display posts from database:
$sql=mysql_query("SELECT * FROM posts WHERE cat='1' ORDER BY date DESC");
But this does not differentiate between if the member has clicked stating they have
seen them yet or not.
I have looked many places and see examples that are close but just cant get any to
fit what I am needing. I don't fully understand how to write this. I have tried many
with no success. If you need extra description please ask. Thank you for your time.
You need to construct a JOIN condition against the posts_read table, or use an IN clause to exclude them. You should be very careful with your indexes as these sorts of queries can get extremely slow and database intensive with non-trivial amounts of data.
SELECT * FROM posts WHERE cat=:cat AND name NOT IN (SELECT postname FROM postsread WHERE memberid=:memberid)
Here :cat and :memberid are placeholders for the appropriate values. Using PDO you can bind directly to those using the execute function.
As a note, joining on strings is a lot slower than joining on id type values. You might want to make your postsread table reference id from posts instead.
sql=mysql_query("SELECT * FROM posts WHERE cat='1' AND name NOT IN (SELECT postname FROM postsread WHERE memberid='$memberid') ORDER BY date DESC") or die (mysql_error());
Tadman was right on with his answer; I had something in the code that was not supposed to be there, but could not find it. Eventually I just rewrote the thing and it worked. The above worked for me, and I thank you Tadman for your help.

Order by votes - PHP

I have a voting script which pulls out the number of votes per user.
Everything is working, except I need to now display the number of votes per user in order of number of votes. Please see my database structure:
Entries:
UserID, FirstName, LastName, EmailAddress, TelephoneNumber, Image, Status
Voting:
item, vote, nvotes
The item field contains vt_img and then the UserID, so for example: vt_img4 and both vote & nvotes display the number of votes.
Any ideas how I can relate those together and display the users in order of the most voted at the top?
Thanks
You really need to change the structure of the voting table so that you can do a normal join. I would strongly suggest adding either a pure userID column, or at the very least not making it a concat of two other columns. Based on an ID you could then easily do something like this:
select
a.userID,
a.firstName,
b.votes
from
entries a
join voting b
on a.userID=b.userID
order by
b.votes desc
The other option is to consider (if it is a one to one relationship) simply merging the data into one table which would make it even easier again.
At the moment, this really is an XY problem, you are looking for a way to join two tables that aren't meant to be joined. While there are (horrible, ghastly, terrible) ways of doing it, I think the best solution is to do a little extra work and alter your database (we can certainly help with that so you don't lose any data) and then you will be able to both do what you want right now (easily) and all those other things you will want to do in the future (that you don't know about right now) will be oh so much easier.
Edit: It seems like this is a great opportunity to use a Trigger to insert the new row for you. A MySQL trigger is an action that the database will make when a certain predefined action takes place. In this case, you want to insert a new row into a table when you insert a row into your main table. The beauty is that you can use a reference to the data in the original table to do it:
CREATE TRIGGER Entries_Trigger AFTER insert ON Entries
FOR EACH ROW BEGIN
insert into Voting values(new.UserID,0,0);
END;
This will work in the following manner - When a row is inserted into your Entries table, the database will insert the row (creating the auto_increment ID and the like) then instantly call this trigger, which will then use that newly created UserID to insert into the second table (along with some zeroes for votes and nvotes).
Your database is badly designed. It should be:
Voting:
item, user_id, vote, nvotes
Placing the item id and the user id into the same column as a concatenated string with a delimiter is just asking for trouble. This isn't scalable at all. Look up the basics on Normalization.
You could try this:
SELECT *
FROM Entries e
JOIN Voting v ON (CONCAT('vt_img', e.UserID) = v.item)
ORDER BY nvotes DESC
but please notice that this query might be quite slow due to the fact that the join field for Entries table is built at query time.
You should consider changing your database structure so that Voting contains a UserID field in order to do a direct join.
I'm figuring the Entries table is where votes are cast (you're database schema doesn't make much sense to me, seems like you could work it a little better). If the votes are actually on the Votes table and that's connected to a user, then you should have UserID field in that table too. Either way the example will help.
Lets say you add UserID to the Votes table and this is where a user's votes are stored than this would be your query
SELECT Users.id, Votes.*,
SUM(Votes.nvotes) AS user_votes
FROM Users, Votes
WHERE Users.id = Votes.UserID
GROUP BY Votes.UserID
ORDER BY user_votes
USE ORDER BY in your query --
SELECT column_name(s)
FROM table_name
ORDER BY column_name(s) ASC|DESC

getting same property from mysql with php

suppose i have 1 current user id and another user id to which current user is visiting.....than i want to fetch mysql data only if both have same options.....
for example user1 has uploaded a picture and user2 has also uploaded picture.......than how can i matchd user1 to user2 and query should be like this........
select * from users where id='user1id' or id='user2id' and imguploaded='1'
is this query is correct or not but it is not working for me..........!!
i want a working query same as above not as
select * from users where imguploaded=1
try ecapsultating your where with brackets, because of the precedence...
select * from users where (id='user1id' or id='user2id') and imguploaded='1'
if you don't mysql will presume default precedence and interpret the query like this:
select * from users where id='user1id' or (id='user2id' and imguploaded='1')
which will not give the desired result.
To check if both users have actually have a picture uploaded you could make it:
select COUNT(*) as count from users where (id='user1id' or id='user2id') and imguploaded='1'
and then check if count==2
Why would you want such a thing like this?
Anyway... create some sort of actions table where you have a structure like id, action, desc Then create a user_action table like id, user_id, action_id. Then fetch your results.
This way you store data in therefore meant tables and don't mess up userdata with their action data. This way you can also easily extend actions and compare users of their made actions.
select * from users where (id='user1id' and imguploaded='1') and (id='user2id'and imguploaded='1')
How about with a join?
query = "SELECT * FROM users AS first JOIN users AS second
ON first.imguploaded = second.imguploaded
WHERE first.userid = $user1 AND second.userid = $user2"
This query would take the two users, and if they have the same attribute (imguploaded is the same for both), return both rows, you can then select what you need. You can add more attributes to the ON clause, for example:
ON first.imguploaded = second.imguploaded OR ( first.imgdloaded = second.imgdloaded AND first.somethingelseuploaded = second.somethingelseuploaded).
This way (with the ON clause of the mysql statement) you can combine all the attributes in the AND/ON but you have to place the brackets - ( and ) - in the right places. Of course, if you don't put them, the MySQL server will just read them serially.
Is that what you need?

Mysql: Getting Count of Comma Separated Values With Like

I decided to use favs (id's of users which marked that post as a favorite) as a comma separated list in a favs column which is also in messages table with sender,url,content etc..
But when I try to count those rows with a query like:
select count(id)
from messages
where favs like '%userid%'
of course it returns a wrong result because all id's may be a part of another's
For example while querying for id=1 it also increase the counter for any other content that is favorited by user id 11...
Can you please tell me your idea or any solution to make this system work?
With a few or's, you can have an ugly solution:
select count(id) from messages where favs like 'userid,%' or favs like '%,userid,%' or favs like '%,userid'
There's likely a more elegant solution, but that one will at least return the result you're looking for, I believe.
Is it possible to change your data model such that the association between users and their favorite messages is instead stored in another table?
Storing the associations in a single column negates the advantages of a relational database. You pay a performance cost using the like function, you can no longer store additional data about the relationship, and the data is harder to query.
An alternative model might looking something like this (can't include an image since I'm a new user, but I made one here):
users
- id
messages
- id
favorite_messages
- user_id (foreign key to users.id)
- message_id (foreign key to messages.id)
With that in place, your original query would be simplified to the following:
select count(1) from favorite_messages where user_id = userid
Additionally, you can do things like get a list of a user's favorite messages:
select
*
from
messages
inner join favorite_messages
on messages.id = favorite_messages.message_id
where
user_id = userid
should using this :
SELECT count(id) FROM messages WHERE FIND_IN_SET('userid',favs) > 0
You might have to get the value, explode it with PHP and then count the array.
There are ways to do it in MySQL, but from what I've seen, they are a hassle.

Categories