I have a website that allows users to be different types. Each of these types can do specific things. I am asking if I should set up 1 table for ALL my users and store the types in an enum, or should I make different tables for each type. Now, if the only thing different was the type it would be easy for me to choose only using one table. However, here's a scenario.
The 4 users are A, B, C, D.
User A has data for:
name
email
User B has data for:
name
email
phone
User C has data for:
name
email
phone
about
User D has data for:
name
email
phone
about
address
If I were to create a single table, should I just leave different fields null for the different users? Or should I create a whole separate table for each user?
Much better if you could create a single table for all of them. Though some fileds are nullable. And add an extra column (enum) for each type of users. If you keep your current design, you will have to use some joins and unions for the records. (which adds extra overhead on the server)
CREATE TABLE users
(
ID INT,
name VARCHAR(50),
email VARCHAR(50),
phone VARCHAR(50),
about VARCHAR(50),
address VARCHAR(50),
userType ENUM() -- put types of user here
)
Another suggested design is to create two tables, one for user and the other one is for the types. The main advantage here is whenever you have another type of user, you don't have to alter the table but by adding only extra record on the user type table which will then be referenced by the users table.
CREATE TABLE UserType
(
ID INT PRIMARY KEY,
name VARCHAR(50)
)
CREATE TABLE users
(
ID INT,
name VARCHAR(50),
email VARCHAR(50),
phone VARCHAR(50),
about VARCHAR(50),
address VARCHAR(50),
TypeID INT,
CONSTRAINT rf_fk FOREIGN KEY (TypeID) REFERENCES UserType(ID)
)
Basic database design principals suggest one table for the common elements and additional tables, JOINed back to the base table, for the attributes that are unique to each type of user.
Your example suggests one and only one additional field per user-type in a straightforward inheritance hierarchy. Is that really what the data looks like, or did you simply for the example? If that's a true representation of your requirements, I might be tempted (for expedience) to use a single table. But if the real requirements are more complex, I'd bite the bullet and do it "correctly".
Try creating four tables:
Table 1: Name, email
Table 2: Name, phone
Table 3: Name, about
Table 4: Name, address
Name is your primary key on all four tables. There are no nulls in the database. You're not storing an enumerated type but derive the type from table joins:
To find all User A select all records in table 1 not in table 2
To find all User B select all records in table 2 not in table 3
To find all User C select all records in table 3 not in table 4
To find all User D select all records in table 4
You should not create tables for different people because this will lead to a bloated database. It's best to create a single table with all the fields you need. If you don't use the field, pass in null values.
I would suggest that you use 1 single table with nullable fields. And a table of something like roles.
Related
I have a tables called userAccounts userProfiles and usersearches.
Each userAccount may have multiply Profiles. Each user may have many searches.
I have the db set up working with this. However in each search there may be several user profiles.
Ie, each user account may have a profile for each member of their family.
They then want to search and include all or some of their family members in their search. The way i would kinda like it to work is have a column in user searches called profiles and basically have a list of profileID that are included in that search. (But as far as i know, you can't do this in sql)
The only way i can think i can do this is have 10 columns called profile1, profile2 ... profile10 and place each profileid into the column and 0 or null in the unused space. (but this is clearly messy )
Creating columns of the form name1...nameN is a clear violation of the Zero, One or Infinity Rule of database normalization. Arbitrarily having ten of them is not the right approach, that's an assumption that will prove to be either wildly generous or too constrained most of the time. Since you're using a relational database, try and store your data relationally.
Consider the schema:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
name VARCHAR(255),
UNIQUE KEY index_on_name (name)
);
CREATE TABLE profiles (
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
user_id INT NOT NULL,
name VARCHAR(255),
email VARCHAR(255),
KEY index_on_user_id (user_id)
);
With that you can create zero or more profile records as required. You can also add or remove fields from the profile records without impacting the main user records.
If you ever want to search for all profiles associated with a user:
SELECT ... FROM profiles
LEFT JOIN users ON
users.id=profiles.user_id
WHERE users.name=?
Using a simple JOIN or subquery you can easily exercise this relationship.
I am building an e learning website. I have three types of users : novice, intermediate and expert. I have 3 tables: lecture,chapter and pages.For each of these table I have to differentiate them by adding for which type of user is that lecture,chapter and page.
Is this a good practice to add same column name category (which can be either novice, intermediate or expert) to all the 3 tables ?
If you want to add more characteristics later to your user categories, the best is to create a separate table for this (eg: user_categories) and refer to this table in all 3 content tables. It would look like this:
CREATE TABLE user_types (id int PRIMARY KEY, name VARCHAR(20));
CREATE TABLE lectures (id int PRIMARY KEY, user_type int REFERENCES user_types(id));
You can also refer to this post to decide how to proceed in your case:How far to take normalization in database design?
I am making a page for a website where customers of the website that rented/bought printers from the company can fill in the amount of printed documents (of every printer they own) in the last period.
Now, I need to translate this to MySQL. The idea is when the customer logs in the webpage it loads an overview with the printers they own, all of them in seperate boxes.
Those boxes each get an input field for the number they are required to submit.
So to make this work I need to put in a Database that, for example, a customer owns 6 different types of printers.
MySQL
--Table for Customers--
create table TBL_Pers (
Clientnr int,
Name varchar,
Post char(6),
Cont char(1),
Contdr tinyint,
p_p_a smallmoney)
--Table for Printer--
create table TBL_Printer (
PNr int,
PBrand varchar,
PName varchar,
Serialnr varchar)
The problem I run with is I have no clue how to link those different printers to a person let alone if I have to deal with 200 customers and 15 different kinds of printers the company offers.
So as you could probably tell I'm pretty new with MySQL :)
You need an association table to relate the two.
This would look like:
create table TBL_Pers_Printer (
Per_Printer_Id int auto_increment primary key,
Clientnr int references TBL_Person(ClientNr),
Pnr int references TBL_Printer(Pnr)
);
You might want to include additional information in this table, such as the date the person got the printer.
What you are looking for is called "many-to-many relationship". You implement it by adding another table:
create table TBL_Pers_Printer (
LnkNr int,
ClientNr int,
PNr int,
foreign key (ClientNr) references TBL_Pers(ClientNr),
foreign key (PNr) references TBL_Printer(PrinterNr)
);
And then insert corresponding pairs of person-printer numbers into it. Here's one of a multitude of resources explaining the concept of many-to-many relationship in a relational database.
You should have a link table TBL_CustomerPrinter (Clientnr, PNr/ SerialNo) where PNr/SerialNo would be the printer, a foreign key and the clientNr would be the client.
the table will allow multiple clients like below
clientID PrinterID
1 1
1 6
1 7
2 8
i.e. define a set of rules for link table:
one client can have multiple printers
one printer can have multiple clients - here is the question - is this possible with your schema?
Basically you need a correspondence table between client and printer, and you have to define a set of rules for this.
Hope this helps
I have a person table and I want users to be able to create custom many to many relations of information with them. Educations, residences, employments, languages, and so on. These might require different number of columns. E.g.
Person_languages(person_fk,language_fk)
Person_Educations(person,institution,degree,field,start,end)
I thought of something like this. (Not correct sql)
create Tables(
table_id PRIMARY_KEY,
table_name_fk FOREIGN_KEY(Table_name),
person_fk FOREIGN_KEY(Person),
table_description TEXT
)
Table holding all custom table name and descriptions
create Table_columns(
column_id PRIMARY_KEY,
table_fk FOREIGN_KEY(Tables),
column_name_fk FOREIGN_KEY(Columns),
rank_column INT,
)
Table holding the columns in each custom table and the order they are to be displayed in.
create Table_rows(
row_id PRIMARY_KEY,
table_fk FOREIGN_KEY(Tables),
row_nr INT,
)
Table holding the rows of each custom table.
create Table_cells(
cell_id PRIMARY_KEY,
table_fk FOREIGN_KEY(Tables),
row_fk FOREIGN_KEY(Table_rows),
column_fk FOREIGN_KEY(Table_columns),
cell_content_type_fk FOREIGN_KEY(Content_types),
cell_object_id INT,
)
Table holding cell info.
If any custom table starts to be used with most persons and becomes large, the idea was to maybe then extract it into a separate hard-coded many-to-many table just for that table.
Is this a stupid idea? Is there a better way to do this?
I strongly advise against such a design - you are on the road to an extremely fragmented and hard to read design.
IIUC your base problem is, that you have a common set of (universal) properties for a person, that may be extended by other (non-universal) properties.
I'd tackle this by having the universal properties in the person table and create two more tables: property_types, which translates a property name into an INT primary key and person_properties which combines person PK, propety PK and value.
If you set the PK of this table to be (person,property) you get the best possible index locality for the person, which makes requesting all properties for a person a very fast query.
I am building an application using MySQL 5.0.77 that contains
a) different user types (e.g. carpenter, mechanic, ..., plumber)
b) different input fields for each user type, e.g. user selects carpenter and is presented with fields pertaining to that profession, where the fields for each profession are different
My thinking is along the lines of:
Table: users
user_id
user_name
Table: carpentry
user_id
woodwork_rating
metalwork_rating
Table: plumbing
user_id
central_heating_rating
bathroom_rating
And so on...
This does not seem very good though since I could potentially end up with lots of tables and users existing in multiple tables with different fields.
I quite like the idea of a metatags table (like we see in Wordpress) so that each users field entry is stored, e.g.
Table: user_info
user_id
field
value
So we would have for example
1 | woodwork_rating | intermediate
1 | metalwork_rating | advanced
2 | woodowork_rating | advanced
My question is, how would you structure a database that has multiple fields for multiple users for which each user only fills in one category of the available fields?
Thanks
Table Users:
UserID: Autoinc PRIMARY KEY
(More user data columns here)
UserType: CHAR(5)
Table UserTypes
UserType: CHAR(5) PRIMARY KEY
Description: VARCHAR(50)
Table UserRatingList
UserRatingCode: CHAR(5) PRIMARY KEY
UserType: CHAR(5) REFERENCES UserTypes
Description: VARCHAR(50)
Table UserRatings
UserID: INTEGER PRIMARY KEY / REFERENCES Users
UserRatingCode: CHAR(5) PRIMARY KEY / REFERENCES UserRatingList
Rating: INTEGER (or whatever you prefer)
The table UserRatingList establishes the pattern of ratings that can be applied to each user type. UserRatings contains the actual ratings. I use CHAR(5) to provider readable codes without having to join in the Description fields, but you can change them to INTEGER if you want.
This structure can also be adapted to allow each user to have multiple types; simply create an addition UserTypeLinks table with UserID and UserType.
i would like to rely on 'mike' s last answer.
i am facing this exact problem. i am creating a network with the following types
Enterprise {name, mail, adress, etc ...}
Employee {name, mail, branch, jobdescription, etc ...}
Individual {name, mail, surname, age, town, etc...}
how about:
Table Users
userID (autoincr)
userType
mailadress
password
...
Table Usertypes
typeID
typeName
typeDescr
Table Enterprises
entID (autoincr)
userID
field 1
field 2
...
Table Employee
empID (autoincr)
userID
...
Table Individuals
indID (autoincr)
userID
...
does this make sense to you?
Are all the fields going to be "ratings" with the same datatype? If so I like Larry Lustig's solution.
Or could there be unrelated fields with different data types? dates, strings, decimals, integers? If so, the first solution of having 1 to 1 related tables that join with Users is OK. As long as you don't need to dynamically add new fields at run time.