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.
Related
Hi, I'm designing a item catalog using MySQL and Squalize ORM (NodeJS).
Suppose I have a product list with different attributes based on its category (attributes_id in this case).
I would like to get a product by using a JOIN statement with an appropriate attribute table. The design should be scalable as we will have more than a hundred attribute tables.
Roughly the statement will look like this:
JOIN
if ( product.attributes_id == 1 ) 'attributes_car'
elseif ( product.attributes_id == 2 ) 'attributes_food'
BUT the the number of elseif cases will grow more than a hundred later.
So the question is how to design attributes_id? Is it a good idea to make it a foreign key to the database metadata (like INFORMATION_SCHEMA) to point to another table? Should I introduce another table to manage such relationship?
One of option is a Dynamic SQL but I don't think it is a good idea because the ifelse cases should grow.
Or should I give up designing a query and just implement such logic on NodeJS side using ORM?
Thank you!
One solution would be to create an additional table that stores attribute_id and table_name.
Create table attibute_tablename(
attribute_id int(11),
table_name varchar(25),
PRIMARY KEY (attribute_id, table_name)
)
You can also add a foreign key to the product table if you want.
Then you only need an insert to this table for every new item added
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 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.
Say I have two tables (Apples and Oranges) with the same columns and just a different table name. Would there be any advantages/disadvantages to turning this into one table (lets say its called Fruit) with an additional column 'type' which would then either store a value of Apple or Orange?
Edit to clarify:
CREATE TABLE apples
(
id int,
weight int,
variety varchar(255)
)
CREATE TABLE oranges
(
id int,
weight int,
variety varchar(255)
)
OR
CREATE TABLE fruit
(
id int,
weight int,
variety varchar(255),
type ENUM('apple', 'orange')
)
Depends on constraints:
Do you have foreign keys or CHECKs on apples that don't exist on oranges (or vice-versa)?
Do you need to keep keys unique across both tables (so no apple can have the same ID as some orange)?
If the answers on these two questions are: "yes" and "no", keep the tables separate (so constraints can be made table-specific1).
If the answers are: "no" and "yes", merge them together (so you can crate a key that spans both).
If the answers are: "yes" and "yes", consider emulating inheritance2:
1 Lookup data is a typical example of tables that look similar, yet must be kept separate so FKs can be kept separate.
2 Specifically, this is the "all classes in separate tables" strategy for representing inheritance (aka. category, subclassing, subtyping, generalization hierarchy etc.). You might want to take a look at this post for more info.
If there really is not any further business rules (and resultant underlying data requirements) that separate the two sub-types then I would use one table with an fk to a FruitType lookup table.
You dont mention what you will be using to access the schema which may affect which approach you take (e.g. if you are using a platform which provides an ORM to your database then this may be worth noting).
The advantage would be normalization. Your tables would then be in 2NF (second normal form).
Your fruit type would be a foreign key to a table with those fruits like so:
CREATE TABLE fruit_type (type varchar(15))
CREATE TABLE fruits (id int, weight int, variety varchar(255), type varchar(15))
I am designing a simple twitter site ( for study ) but with a little bit different: the users can follow other users, keywords and lists. I want to know how to create a following table to put information about following.
Is this approach ( below ) correct ?
Following Table:
id ( id of the following table )
type ( type can be 1 ( user ), 2 ( keyword ) or 3 ( list ) )
idtype ( id of the type table )
user ( user's id )
However there isn't a keyword table. So I don't know.
What is the best approach ?
It's incorrect because you can't create a foreign key from idtype to the parent table, because "parent table" changes depending on type. BTW, if user can follow multiple keywords, then you won't escape having a separate table for that (unless you want to break the 1NF by "packing" several values into the same field, which is a really bad idea).
There are couple of ways to resolve this, probably the simplest one is to use separate id fields for each of the possible parent tables, and then constrain them so only one of them can be non-NULL.
However, since InnoDB tables are clustered and secondary indexes in clustered tables are expensive, I'd rather go with something like this (tweets table not shown):
This will enable you to very efficiently answer the query: "which users follow the given user (or keyword or list)". If you need to answer: "which users (or keywords or lists) the given user follows", reverse the order of fields in the PKs shown above. If you need both, then you'd need indexes in both directions (and pay the clustering price).