I want to display posts from the users being followed and the logged in user using a single PHP mysql query.
I have three tables:
- Users (id, name, password)
- Posts (id, body, date, user_id)
- Followers (id, user_id, follower_id)
followers.follower_id = person who does the following
followers.user_id = person who is being followed
$_SESSION['id'] = id of the logged in user
DB::query('
SELECT users.name, posts.body
FROM users, posts, followers
WHERE posts.user_id = followers.user_id
AND users.id = posts.user_id
AND followers.follower_id = :userid',
array(':userid'=>$_SESSION['id'])
);
But the query only shows posts from the users being followed, not from the logged in user. How do I fix this?
I have already created a relation between the posts table and the users table.
CREATE TABLE `posts` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`body` varchar(160) NOT NULL DEFAULT '',
`user_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
You need to include 2 criteria in your WHERE clause: Either the creator of the post matches your :userid variable, or the follower matches your :userid.
Please use current join syntax: This makes your query a lot easier to read.
Your final query should be something like this (I'm excluding the PHP part):
SELECT users.name, posts.body
FROM posts
INNER JOIN users ON
users.id = Posts.user_id
-- use left join to handle when a
-- user has no followers
LEFT JOIN Followers ON
Followers.user_id = users.user_id
WHERE
users.id = :userid
OR followers.follower_id = :userid
Related
I have 3 tables: users, games and players. For simplicity's sake, I will say that the tables look like this:
users
id int AUTO_INCREMENT,
PRIMARY KEY (id)
games
id int AUTO_INCREMENT,
PRIMARY KEY (id)
players
game_id int,
user_id int,
FOREIGN KEY (game_id) REFERENCES (games.id),
FOREIGN KEY (user_id) REFERENCES (users.id)
I need to select users.id where players.game_id is 1
so far I have tried
SELECT users.id FROM users, game_users WHERE players.id = 1
and also some SELECT statements with INNER JOINs but to no avail.
if only need user_id don't need JOIN just
SELECT user_id
FROM players
WHERE game_id =1
Now if you need the names a single JOIN will work
SELECT users.name
FROM players
JOIN users
ON player.user_id = users.id
WHERE game_id =1
you must have a join key to join users and games. as
...WHERE game_users.id = 1 AND users.id=game_users.id
And you don't have a table called game_users
Ok we have inbox table where we keep messages that users send to each other. Here is the table:
CREATE TABLE IF NOT EXISTS `inbox` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`fromid` int(10) unsigned NOT NULL DEFAULT '0',
`toid` int(10) DEFAULT NULL,
`message` text CHARACTER SET utf8 NOT NULL,
`time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `toid` (`toid`),
KEY `fromid` (`fromid`),
KEY `fromid_2` (`fromid`,`toid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
fromid and toid are id's of the users. We have their id's, times when the message is sent. What we need is a query that would return all messages that are not replied by 'our users' (admins).
Table accounts keeps track of users. To simplify:
CREATE TABLE IF NOT EXISTS `accounts` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`our` int(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
So basically, we need a query that gives us the users WHOSE messages WERE NOT ANSWERED by admins (our users), their count and the date of the last message they sent to ADMIN, ordered from last to oldest.
So far we only have some basic queries, we didn't come up with anything reasonable that I could post.
Thanks in advance.
EDIT: From what I see we first need to find last interaction from two DISTINCT users in inbox table... then check & filter only those that were sent TO our users
How about this?
SELECT i.* FROM inbox as i
WHERE (i.toid, i.fromid) NOT IN
(SELECT i2.fromid, i2.toid FROM inbox as i2 WHERE i2.`time` >= i1.`time` AND i2.id = 1);
Another way using join:
SELECT DISTINCT i1.*
FROM inbox as i1 LEFT JOIN inbox as i2
ON i1.toid = 1 AND
i1.fromid = i2.toid AND
i1.toid = i2.fromid AND
i1.`time` <= i2.`time`
WHERE i2.id IS NULL;
Two possible solutions presented below: LEFT JOIN solution should perform better.
LEFT JOIN solution
SELECT
i.fromid, COUNT(*) AS unread, MAX(i.time) AS lastmsg
FROM inbox AS i
INNER JOIN accounts AS a
ON i.toid = a.id
LEFT JOIN inbox AS i2
ON i.fromid = i2.toid AND i.toid = i2.fromid AND i.time <= i2.time
WHERE a.our = 1 AND i2.id IS NULL
GROUP BY i.fromid
ORDER BY lastmsg DESC;
NOT IN solution
SELECT
i.fromid, COUNT(*) AS unread, MAX(i.time) AS lastmsg
FROM inbox AS i
INNER JOIN accounts AS a ON i.toid = a.id
WHERE a.our = 1 AND
(i.toid, i.fromid)
NOT IN (SELECT i2.fromid, i2.toid FROM inbox AS i2 WHERE i2.time >= i.time)
GROUP BY i.fromid
ORDER BY lastmsg DESC;
Web application PHP,Mysql. Users can write articles. How to build algorithm that allows users to subscribe (follow) to other users articles and then see list of last articles added by subscribed users? Algorithm must scale, so that one user can subscribe to 10 000 users and 10 000 users can subscribe to one user and all parts works quick - when new article added and when users looks for last articles from subscribed users.
create table `user`(
`id` INT(10) PRIMARY KEY NOT NULL AUTO_INCREMENT
);
create table `subscribes_to` (
`subscriber_user_id` INT(10) NOT NULL,
`subscribed_to_user_id` INT(10) NOT NULL, # Receiver of the subscription
PRIMARY KEY(`subscribe_user_id`, `subribed_to_user_id`),
KEY `subscriber(`subscribe_user_id`),
KEY `subscribed(`subscribed_to_user_id`);
);
# Users subscribed to role 100
SELECT distinct u.* FROM user u
JOIN subscribes_to st ON st.subscriber_user_id = u.id
WHERE
st.subscribded_to_user_id = 100;
# User 100's subsriptions
SELECT distinct u.* FROM user u
JOIN subscribes_to st ON st.subscribded_to_user_id = u.id
WHERE
st.subscriber_user_id = 100;
Additional Schema to show relationship with articles:
article (
id int(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255),
body TEXT,
date_created DATETIME,
date_updated DATETIME,
author_user_id int(10)
);
# Create new article
INSERT INTO `article` VALUES (NULL, "Hello", "This is the body", NOW(), NOW(), 1);
# Find the last 10 articles posted that user 15 suscribes to
# the author of
SELECT a.* FROM article a
JOIN user ON u.id = a.author_user_id
JOIN subscribes_to st ON st.subscribed_to_user_id = u.id
WHERE st.subscriber_user_id = 15 ORDER BY a.date_created DESC LIMIT 10;
I need help on making a friend-system.
I am thinking how to make so both users can see that they are friends together.
Should i just make a user1 field and user2 field, and then when displaying him/her´s friends, it should select where user1 ='$id' OR user2 = '$id' ?
Or should i make two rows each time people are being friends?
Smart way and example would be appreciated. Thank you.
I am storing in mysql database.
My thoughts is exactly in how should i list that who is friend with who. Lets say i use method 1) with user1 and user2 column, then i should have WHERE user1 or user2 is $id (users id) but can this work properly?
I just tried this and it shows the userid for user2 in user1´s friendslist,
but in user2´s friendslist it just shows his own userid and not the user1s..
On a big projects with sharding you should always replicate data for each user.
For not so big project it's okay to keep one table with "initiator" and "accepter" fields for user_id. Don't forget to add indexes and "status" field for friendship
I'm assuming you're storing them in a database. A simple way would be to have a new table, lets call it "friendships" with two columns, user_1, user_2. If two users are friends, they should have a row in this table. This is an extremely simple way of implementing this, but it should work.
SELECT users.name, fr.name
FROM users, friends, users AS fr
WHERE users.user_id = ?
AND users.user_id = friends.user_id1
AND friends.user_id2 = fr.user_id
UNION
SELECT users.name, fr.name
FROM users, friends, users AS fr
WHERE users.user_id = ?
AND users.user_id = friends.user_id2
AND friends.user_id1 = fr.user_id
This will allow you check against an intermediary table for your many-to-many relationship and not have to duplicate (inverse) rows.
CREATE TABLE `users` (
`user_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`user_id`),
);
CREATE TABLE `friends` (
`user_id1` bigint(20) unsigned NOT NULL,
`user_id2` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`user_id1`,`user_id2`)
);
Some good answers here, If I had to do this I would do it one way, this way you can determine if the friendship has been confirmed and also ensure the friendship is mutual, so for example
Lets assume status has two values
0 = Unconfirmed
10 = Confirmed
Using simple tables with status for acceptance levels
CREATE TABLE `users` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`user_id`),
);
CREATE TABLE `friend` (
`user_id` bigint(20) unsigned NOT NULL,
`friend_id` bigint(20) unsigned NOT NULL,
`status` int(11) unsigned NOT NULL,
PRIMARY KEY (`user_id`,`friend_id`)
);
INSERT INTO `users` (`id`, `name`) VALUES
(1, 'Jack'),
(2, 'John');
Jack would like to be friends with John, so you would create a relationship between the two only one way:
INSERT INTO `friend` (`user_id`, `friend_id`, `status`) VALUES (1, 2, 0);
Now you can query the database to find Jacks friends or Jacks requests and Johns friends or Johns requests using simple queries
To find Jacks unconfirmed friends you would use something like
SELECT users.* FROM users JOIN friend ON users.id = friend.user_id WHERE friend.friend_id = 1 AND friend.status = 0
To find Jacks confirmed friends you would use something like
SELECT users.* FROM users JOIN friend ON users.id = friend.user_id WHERE friend.friend_id = 1 AND friend.status = 10
To find Jacks any friend requests you would use something like
SELECT users.* FROM users JOIN friend ON users.id = friend.user_id WHERE friend.friend_id = 1
When someone makes a confirmation of friendship you would perform 2 queries, one for updating the record and one as a reverse confirmation
UPDATE friend SET status = 10 WHERE user_id = 1 AND friend_id = 2;
INSERT INTO `friend` (`user_id`, `friend_id`, `status`) VALUES (2, 1, 10);
On a different note, I would also use a Graph database for complex relationship queries whilst maintaining a firm copy in the MySQL database
Graph teaser for friends of friends to build relationships
MATCH (Person { id: 1 })-[:knows*2..2]->(friend_of_friend) WHERE NOT (Person)-[:knows]->(friend_of_friend) AND NOT friend_of_friend.id = 1 RETURN friend_of_friend.id, friend_of_friend.name LIMIT 10
Say I have three tables in my database:
CREATE TABLE `users` (
`user_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR(16) NOT NULL
);
CREATE TABLE `users_meta` (
`meta_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`user_id` INT NOT NULL ,
`key` VARCHAR(200) NOT NULL ,
`value` TEXT NOT NULL
);
CREATE TABLE `posts` (
`post_id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`user_id` INT NOT NULL ,
`content` TEXT NOT NULL
);
The table users_meta is just a key-value store of information about users, such that we can add any piece of information we want.
Say I added a key => value pair to the users_meta table for each user where the key was "age", and the value was a number representing their age.
Given this set of circumstances, what's the best way to select the first 10 posts ordered by user age?
I like putting the condition of the join in the join itself to be clear that I want a limited join:
SELECT p.post_id, p.content
FROM users u
INNER JOIN users_meta um
ON (u.user_id = um.user_id) AND um.key = 'age'
INNER JOIN posts p
ON (p.user_id = u.user_id)
ORDER BY um.value
limit 10
If you order by user age only, you will select 10 posts of the same user (the youngest one).
I would suggest to denormalize and store age in users table directly.
Agree with #KOHb, but if that's exactly what you want, here is the query:
SELECT TOP 10 p.id, p.content
FROM users u JOIN users_meta um ON (u.user_id = um.user_id)
JOIN posts p ON (p.user_id = u.user_id)
WHERE um.key = 'age'
ORDER BY um.value