I've currently got two tables:
mems (members):
id,
name,
email,
password,
salt,
achievements_id
achievements:
id,
achievement,
description,
points
I am able to correctly display the data for a user with:
"SELECT * FROM achievements WHERE id IN (SELECT achievements_id FROM mems WHERE name = '$name')";
My question is, how do I add the achievement ID to the user so each user has their own achievement records? Currently if I use an update it just wipes over the old achievement so it only ever displays 1 record.
Say I have 2 achievements and 2 users
User 1 achieves achievement 1, it's viewable and they have achievements_id set to 1.
User 2 achieves achievement 1, it's viewable and they have achievements_id set to 1.
User 1 then achieves achievement 2, it's viewable but now they have achievements_id set to 2.
I have no clue how to do this. I know what I want to do, but no clue how to design the database to have each user having their own records of achievements.
I originally did it where achievements table had a member_id and I'd concat the other users ID into their, dodgy but it semi-worked.
Any help? Sorry if I am making no sense.
It sounds like what you need is to model a many-to-many relationship (many users can share the same achievement - ie. be linked to the same entitiy in the achievements table; while a single user can have multiple achievements). This is usually done using an extra table. Let's call it: Members_Achievements_Map.
CREATE TABLE Members_Achievements_Map (
MemberID,
AchievementID
)
This table would link entities from the members table to entities in the achievements table.
The way I would go about this would be to create another table to hold the users achievements.
So basically another table that looks like such:
UserAchievements:
userID, achievementID
That way you can join the tables like:
SELECT * FROM achievements a
INNER JOIN userAchievements uA ON uA.achievementID = a.id
INNER JOIN users u ON uA.userID = u.id
That will give you all the users for all the different achievements.
Hope that helps!
Related
I am creating a site that allows users to view desired 'teams' and can then join them with the click of one button.
I have my users table which contains: user_id, user_name, team_id
Then, I have my teams table which contains: team_id, team_name, team_players
How would I go about having the users to join a group, each user can also only be in 1 team at a time.
If you want each user to be able to join multiple teams, and each team to have multiple users, then you need a "join table."
Table teams_users would contain team_id, user_id. You can make a composite primary key on team_id, user_id (preventing a user from joining the same team twice).
Then you can get a team with:
SELECT * FROM users t1 right join teams_users t2 ON t1.team_id = t2.team_id WHERE t2.team_name = 'the rascals'
Even if you only want players to join one team at a time, you might still want to use the join table in case you ever change your mind. It would be very easy. To only allow one team per user, put a unique constraint on user_id in the join table. If you later decide you want to allow multiple teams, you just remove that constraint.
If a user tries the "join team" action, you simply check for the user_id's existence in the join table.
SELECT * FROM teams_users WHERE user_id = $user_id
If it does exist, you retrieve its matching team_id and tell them, "sorry, you are already in team 'the rascals'. You must leave that team if you want to join another." If they drop their team, you simply do:
DELETE from teams_users WHERE user_id = 5
If they add a team, you just do:
INSERT INTO teams_users ($team_id, $user_id) #// (assuming PHP variables).
The INSERT query will only work if they are not already in a team. If they are you would get an error message. You could also look at "INSERT ON DUPLICATE KEY UPDATE ..." queries. But I would advise against that because you want to warn users before they change teams.
You should start by adding the team_id field to the users table as a foreign key and allow it to be NULL.
Then you would display the team names in an html form with a radio button for each team.
In a PHP file (which should be set to the action of your form) create an if statement based on the values you assigned to each radio button. In each if block, execute a sql UPDATE statement that will add the appropriate group_ID to the right user instance.
Okay I am making a profile page where I will call on all of the user's information. Within the website users will gain points and earn badges. I have something like 35 badges. Rather than have a row in my users table for every badge(yes/no to decide whether user has earned badge) for every single user, I was wondering how I could do this without blowing up my users table.
I have a badge table with index, name, description, and photo. I was wondering can I make a single row in my users table for badges and separate badge numbers by ",". Then decipher the badges so they all print on the page. I feel I can do this but don't know how.
Please help. Open to other suggestions
You are describing a many-to-many relationship; use a junction table to represent it.
Create a table of users and a table of badges. Then create a Users_Badges table with user_id and badge_id as foreign keys in it (together they will form a composite key).
you can create table structures like these.
table structures
users
userId
userName
badges
badgeId
badgeName
user_badges
userId
badgeID
-- returns given users all badges within single row and comma seperated field.
select group_concat(b.badgeName) as usersAllBadges
from user_badges ub
inner join users u on u.userId = ub.userId
inner join badges b on b.badgeId = ub.badgeID
where ub.userID=1
-- returns given users all badges seperate rows.
select b.badgeName
from user_badges ub
inner join users u on u.userId = ub.userId
inner join badges b on b.badgeId = ub.badgeID
where ub.userID=1
You tagged php so I am assuming php
explode(',',$data);
http://www.php.net
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.
I'm new to advanced MySQL having only come across many-to-many relationships yesterday. I'm working on a project where users can join multiple projects and projects can accommodate multiple users.
My tables are:
Users - ID, name, email, password etc
Projects - ID, name, URL etc
Following advice from this site, I have set up a linking table with two foreign keys matched to the IDs of the above tables:
Users_Projects - Users_ID, Projects_ID
I understand the next step is something to do with joining, but how do I add a user to a table, or see who the members of a project are/what projects a particular user is a member of?
Projects for a given user:
SELECT *
FROM Projects p
LEFT JOIN users_projects up ON p.projects_id = up.projects_id
WHERE up.users_id = [INSERT USERID HERE]
To assign user to project you need to type user id and project id into the User_Projects table, to see which users are in selected project you can type:
SELECT Users.name, Users.email etc.. from Users_Projects JOIN Users on Users.ID =
Users_Projects.Users_ID JOIN Projects ON Projects.ID = Users_Projects.Projects_ID WHERE (Put your where statement here)
Read more on wiki: JOIN wikipedia
I think you forgot an id (in users, create new fields 'projectid' on user table)
ADD USER => INSERT INTO users (name,email,...) VALUES ('fred','redeyes#XX.com',...);
CHECK USER => SELECT name, email FROM USERS;
CHECK USER BY PROJECT ID => SELECT name, email FROM USERS, PROJECTS WHERE USERS.projectid = PROJECTS.id
I have a social network similar to myspace/facebook. In my code you are either a person's friend or not a friend, so I show all actions from people you are friends with (in this post I will refer to actions as bulletin posts alone to make it easier to visualize.
So you every time a person post a bulletin it will show up to any person who is there friend.
In mysql you would get a persons friend list by doing something like this,
SELECT user_id FROM friends WHERE friend_id = 1 (user ID)
I want to know how a site like facebook and some others would show all bulletin post from your friends and from your friends' friends?
If anyone has an idea please show some code like what kind of mysql query?
The answer is that they aren't doing selects on a friend table, they are most likely using a de-normalized news-event table. We implemented a news-feed similar to Facebooks on DoInk.com, here's how we did it:
There is the notion of a "NewsEvent" it has a type, an initiator (a user id) and a target user (also a user id). (You can also have additional column(s) for other properties relevant to the event, or join them in)
When a user posts something on another users wall we generate an event like this:
INSERT INTO events VALUES (wall_post_event, user1, user1)
When viewing user1's profile, you'd select for all events where user1 is either the initiator or the target. That is how you display the profile feed. (You can get fancy and filter out events depending on your privacy model. You may consider doing this in memory for performance reasons)
Example:
SELECT * FROM events WHERE initiator = user1 or target = user1 //to see their profile feed
SELECT * FROM events WHERE initiator IN (your set of friend ids) //to see your newsfeed
When you want to see the newsfeed for all events relative to your friends you might do a query selecting for all events where the initiator is in your set of friends.
Avoid implementations with sub-selects, depending on the complexity, they will not scale.
you do a subquery:
SELECT DISTINCT user_id FROM friends WHERE friend_id IN
(SELECT user_id FROM friends WHERE friend_id = 1)
Test both of these for performance:
SELECT DISTINCT user_id
FROM friends f1
JOIN friends f2 ON f1.friend_id = f2.user_id
WHERE f2.friend_id = 1
and
SELECT DISTINCT user_id
FROM friends
WHERE friend_id IN (SELECT user_id FROM friends WHERE friend_id = 1)
Often they're the same but sometimes they're not.
Make sure friend_id and user_id are indexed.
The simple approach would be to do some kind of simple nested clause. So say you have a table with posts and the posters id, and a friends table, the first layer would be
SELECT post FROM posts JOIN friends
on post.userid = friends.friend_id
WHERE friend.id = 1 (user ID)
then to get a friends of friends
SELECT post FROM posts JOIN
(SELECT DISTINCT friends_2.friend_id FROM friends AS friends_1
JOIN friends as friends_2
on friends_1.friend_id = friends_2.id where friends_1.id = 1)
AS friends
wHERE post.userid = friends.friend_id AND mainid = 1 (user ID)
You can repeat this nesting each time you want to add another layer of friend abstraction. The problem with this approach is that it would take a very long time to execute. For every time you add a layer of friend abstraction you are increasing the complexity by a power of n (where n is the number of rows in your table).
It is more likely that they are saving the viewable friends in a table somewhere, so lets make a new tabled called friends_web
user_id, friend_id, level
when a user friends someone, it adds that new friend into friends_web at a level of 0(since that friend is no people away) then adds that friends friends at a level of 1 (since its 1 friend away). In order to keep the table integrity you would also want to add the inverted record. To clarify if A adds B as a friend and C is a friend of B, the following two records would get added to our new table
A, C, 1
C, A, 1
since now A can see C and C can see A.
now when we want a query we just do
SELECT post FROM posts
JOIN friends_web ON post.user_id = friends_web.friend_id
WHERE friends_web.user_id = user_id AND friends_web.level < 2 (or however deep you want to look)
by doing that you minimized your query complexity when doing post lookups while being able to look more then 1 layer deep into a friend web.
Sorry for the long winded response.
This should pull out all the user's friend's posts.
SELECT * FROM posts WHERE uid IN (SELECT friend_uid FROM friends WHERE uid=1) ORDER BY post_id DESC
This should pull out all posts that are your friend's friend's.
SELECT * FROM posts WHERE uid IN (SELECT friend_uid FROM friends WHERE uid IN (SELECT friend_uid FROM friends WHERE uid=1)) ORDER BY post_id DESC