Im making a simple score keeping system and each user can have stats for many different games
But i don't know if each user should have his own score table or have one big table containing all the scores with a user_id column
Multiple Tables:
table name: [user id]_score
game_id | high_score | last_score | average_score
Single Table:
user_id | game_id | high_score | last_score | average_score
Definitely have a single table with the userID as one of the fields. It would be very difficult (and needlessly so) to deal with multiple tables like that.
You will likely want at least one index to include the userId field, so that the records for each userId can be quickly found by queries.
Go with a single table and a composite primary key around user_id and game_id. You may also want to create a supplementary index around game_id so that lookups of high scores by game are fast. (The composite key will not suffice if user_id is not part of the criteria as well.)
Using a one-table-per-user approach would be cause for some LARTing.
Keep one table with all of the user_ids in them, definitely. Generally, you want to stay away from any solution that involves having generated data (userIDs) in table names (there are exceptions, but they're rare).
you'll probably want:
a user table user_info[], user_id
a game table game_info[], game_id
a user_game_join table that holds user_id, game_id, score, insertdate
that way you have all the data to get high score by game, by user, by game & user, averages & whatnot or whatever else.
always build extensibly. you never know when you will need to refine your code and redoing a database is a real PITA if you don't lay it our right to start with.
Related
I have a users table and a scores table:
-------- users
Name | Type
------------------------|----------------
uuid | VARCHAR(36)
name | VARCHAR(255)
... | ...
-------- scores
Name | Type
------------------------|----------------
uuid | VARCHAR(36)
user_uuid | VARCHAR(36)
score | INT(11)
I can fetch a user, including their total score using a subquery like this:
SELECT user.uuid, user.name,
(SELECT SUM(score) FROM scores WHERE user_uuid = user.uuid) AS score
FROM user WHERE user.uuid = [USER_UUID];
But now, how can I fetch the user's rank? That is, rank being determined by their score vs the scores of every other user.
Is it really necessary to loop through every single user, calculate all of their scores, and then order their scores to determine the rank of one single user? Performing this query on the fly seems taxing, especially if I have a large number of users. Should I instead build a separate rankings table, and re-sort the table after each INSERT into the scores table? That doesn't seem ideal either.
I have another application which will require on-the-fly ranking as well, but the calculations are much more severe: a user's score is determined by a complex algorithm spanning at least 5 different tables. So I really need some insight on database ranking in general - although the above problem is an easy way to represent it. What are some good practices to consider?
I think keeping the rank of each user in a different table(using a procedure when inserting data to the scores table) would be better. So that you can get the rank straight away when you need.
refer the mark as correct answer in this link. It might help you.
rank function in sql
i'm building a study tool and i'm not sure of the best way to go about structuring my database.
Basically, i have a simple but big table with around 50000 bits of information in it.
info (50'000 rows)
id
info_text
user
id
name
email
password
etc
What i want is for the students to be able to marked each item as studied or to be studied(basically on and off), so that they can tick off each item when they have revised it.
I want to build tool to cope with thousands of users and was wondering what the most efficient/easiest option way of setting up the database and associated queries.
At the moment i would lean towards just having one huge table with two primary keys one with user id and then id of the info they had studied and then doing some sort of JOIN statement so i could only pull back the items that they had left to study.
user_info
user_id
info_id
Thanks in advance
Here is one way to model this situation:
The table in the middle has a composite primary key on USER_ID and ITEM_ID, so a combination of the two must be unique, even though individually they don't have to be.
A user (with given USER_ID) has studied a particular item (with given ITEM_ID) only if there is a corresponding row in the STUDIED table (with these same USER_ID and ITEM_ID values).
Conversely, the user has not studied the item, if and only if the corresponding row in STUDIED is missing. To pull all items a given user hasn't studied, you can do something like this:
SELECT * FROM ITEM
WHERE NOT EXISTS (
SELECT * FROM STUDIED
WHERE
USER_ID = <given_user_id>
AND ITEM.ITEM_ID = STUDIED.ITEM_ID
)
Or, alternatively:
SELECT ITEM.*
FROM ITEM LEFT JOIN STUDIED ON ITEM.ITEM_ID = STUDIED.ITEM_ID
WHERE USER_ID = <given_user_id> AND STUDIED.ITEM_ID IS NULL
The good thing about this design is that you don't need to care about STUDIED table in advance. When adding a new user or item, just leave the STUDIED alone - you'll gradually fill it later as users progress with their studies.
I would do something like this:
1) A users table with a uid primary key
2) A enrolled table (this table shows all courses that have enrolled students) with a primary key of (uid, cid)
3) A items (info) table holding all items to study, with a primary key of itemid
Then in the enrolled table just have one attribute (a binary flag) 1 means it has been studyed and 0 means they still need to study it.
I'm working on redesigning some parts of our schema, and I'm running into a problem where I just don't know a good clean way of doing something. I have an event table such as:
Events
--------
event_id
for each event, there could be n groups or users associated with it. So there's a table relating Events to Users to reflect that one to many relationship such as:
EventUsers
----------
event_id
user_id
The problem is that we also have a concept of groups. We want to potentially tie n groups to an event in addition to users. So, that user_id column isn't sufficient, because we need to store potentially either a user_id or a group_id.
I've thought of a variety of ways to handle this, but they all seem like a big hack. For example, I could make that a participant_id and put in a participant_type column such as:
EventUsers
----------
event_id
participant_id
participant_type
and if I wanted to get the events that user_id 10 was a part of, it could be something like:
select event_id
from EventUsers
where participant_id = 10
and participant_type = 1
(assuming that somewhere participant_type 1 was defined to be a User). But I don't like that from a philosophical point of view because when I look at the data, I don't know what the number in participant_id means unless I also look at the value in particpant_type.
I could also change EventUsers to be something like:
EventParticipants
-----------------
event_id
user_id
group_id
and allow the values of user_id and group_id to be NULL if that record is dealing with the other type of information.
Of course, I could just break EventUsers and we'll call it EventGroups into 2 different tables but I'd like to keep who is tied to an event stored in one single place if there's a good logical way to do it.
So, am I overlooking a good way to accomplish this?
Tables Events, Users and Groups represent the basic entities. They are related by EventUsers, GroupUsers and EventGroups. You need to union results together, e.g. the attendees for an event are:
select user_id
from EventUsers
where event_id = #event_id
union
select GU.user_id
from EventGroups as EG inner join
GroupUsers as GU on GU.group_id = EG.group_id
where EG.event_id = #event_id
Don't be shy about creating additional tables to represent different types of things. It is often easier to combine them, e.g. with union, than to try to sort out a mess of vague data.
Of course, I could just break EventUsers and we'll call it EventGroups into 2 different tables
This is the good logical way to do it. Create a junction table for each many-to-many relationship; one for events and users, the other for events and groups.
There's no correct answer to this question (although I'm sure if you look hard enough you'll finds some purists that believe that their approach is the correct one).
Personally, I'm a fan of the second approach because it allows you to give columns names that accurately reflect the data they contain. This makes your SELECT statements (in particular when it comes to joining) a bit easier to understand. Yeah, you'll end up with a bunch of NULL values in the column that is unused, but that's not really a big deal.
However, if you'll be joining on this table a lot, it might be wise to go with the first approach, so that the column you join on is consistently the same. Also, if you anticipate new types of participant being added in the future, which would result in a third column in EventParticipants, then you might want to go with the first approach to keep the table narrow.
I have a pretty typical user table setup for my web application:
user_id | username
--------------------
0 greg
1 john
... ...
Both fields are indexed and unique, so I can look up a user by id or username quickly.
I want to keep a friends table, and am not sure whether to store the user_id values or usernames in that table:
user_id_1 | user_id_2
--------------------------
or
username_1 | username_2
--------------------------
I am going to want to get a list of friends for a user, so it would be convenient to immediately have the usernames in the friends table instead of doing a join on the users table:
select * from friends where username_1 = 'greg';
If I'm storing user ids, I need to do a join then to get the usernames - will that be costly?:
select * from friends
where user_id_1 = x
join users where user_id = { all those results }
Using user ids allows me to let users change usernames flexibly, but I'm not letting them do that anyway. Any advice would be great.
Thanks
A join on the IDs won't be too bad. The ID may be smaller to store on disk. Also, I would imagine a list of friends would have something other than just user names, in which case, you have to join no matter what.
Well, as you said, using id semantics means you can change the username without having to deal with cascading effects. For most cases PK / UNQ + FK indexes will make joins thundering fast, but you may have a point for huge tables (for which you will eventually need some kind of external index, or other tool anyway).
The ID will be smaller if you use numeric values. Also the index search will be faster. Here you'll find the data types for MySQL 5.0.
Also I don't know how are you using index, but I'd recommend to add and auto-increment field. You can do that to a table, for an integer index like this:
ALTER TABLE `Database`.`tableName` ADD COLUMN `indexName` INTEGER NOT NULL AUTO_INCREMENT
I'm planing to build some database project.
One of the tables have a lot of attributes.
My question is: What is better, to divide the the class into 2 separate tables or put all of them into one table. below is an example
create table User { id, name, surname,... show_name, show_photos, ...)
or
create table User { id, name, surname,... )
create table UserPrivacy {usr_id, show_name, show_photos, ...)
The performance i suppose is similar due to i can use index.
It's best to put all the attributes in the same table.
If you start storing attribute names in a table, you're storing meta data in your database, which breaks first normal form.
Besides, keeping them all in the same table simplifies your queries.
Would you rather have:
SELECT show_photos FROM User WHERE user_id = 1
Or
SELECT up.show_photos FROM User u
LEFT JOIN UserPrivacy up USING(user_id)
WHERE u.user_id = 1
Joins are okay, but keep them for associating separate entities and 1->N relationships.
There is a limit to the number of columns, and only if you think you might hit that limit would you do anything else.
There are legitimate reasons for storing name value pairs in a separate table, but fear of adding columns isn't one of them. For example, creating a name value table might, in some circumstances, make it easier for you to query a list of attributes. However, most database engines, including PDO in PHP include reflection methods whereby you can easily get a list of columns for a table (attributes for an entity).
Also, please note that your id field on User should be user_id, not just id, unless you're using Ruby, which forces just id. 'user_id' is preferred because with just id, your joins look like this:
ON u.id = up.user_id
Which seems odd, and the preferred way is this:
ON u.user_id = up.user_id
or more simply:
USING(user_id)
Don't be afraid to 'add yet another attribute'. It's normal, and it's okay.
I'd say the 2 separate tables especially if you are using ORM. In most cases its best to have each table correspond to a particular object and have its field or "attributes" be things that are required to describe that object.
You don't need 'show_photos' to describe a User but you do need it to describe UserPrivacy.
You should consider splitting the table if all of the privacy attributes are nullable and will most probably have values of NULL.
This will help you to keep the main table smaller.
If the privacy attributes will mostly be filled, there is no point in splitting the table, as it will require extra JOINs to fetch the data.
Since this appears to be a one to one relationship, I would normally keep it all in one table unless:
You would be near the limit of the number of bytes that can be stored in a row - then you should split it out.
Or if you will normally be querying the main table separately and won't need those fields much of the time.
If some columns is (not identifiable or dependent on the primary key) or (values from a definite/fixed set is being used repeatedly) of the Table make a Different Table for those columns and maintain a one to one relationship.
Why not have a User table and Features table, e.g.:
create table User ( id int primary key, name varchar(255) ... )
create table Features (
user_id int,
feature varchar(50),
enabled bit,
primary key (user_id, feature)
)
Then the data in your Features table would look like:
| user_id | feature | enabled
| -------------------------------
| 291 | show_photos | 1
| -------------------------------
| 291 | show_name | 1
| -------------------------------
| 292 | show_photos | 0
| -------------------------------
| 293 | show_name | 0
I would suggest something differnet. It seems likely that in the future you will be asked for 'yet another attribute' to manage. Rather than add a column, you could just add a row to an attributes table:
TABLE Attribute
(
ID
Name
)
TABLE User
(
ID
...
)
TABLE UserAttributes
(
UserID FK Users.ID
Attribute FK Attributes.ID
Value...
)
Good comments from everyone. I should have been clearer in my response.
We do this quite a bit to handle special-cases where customers ask us to tailor our site for them in some way. We never 'pivot' the NVP's into columns in a query - we're always querying "should I do this here?" by looking for a specific attribute listed for a customer. If it is there, that's a 'true'. So rather than having these be a ton of boolean-columns, most of which would be false or NULL for most customers, AND the tendency for these features to grow in number, this works well for us.