MySQL table (re)design - mysql

We have "user" and "study" entities in our application, stored in their respective tables.
A study represents a kind of research and the data that has been gathered.
They have a many-to-many relationship, so we need a linking table: studies_users.
We assign roles to users. There are a few "normal" roles, which are study-dependent, so for the same user they can be different, depending on the chosen study. This means that those kind of roles would have to be stored as part of the studies_users table.
There is however a request for a new, "special" role, lets call it superadmin, which basically means the user has all possible roles (or rights) in all kinds of studies. That means such property wouldn't have to be stored in the studies_users linking table, it's sufficient to store it in the users table in a new column (is_superadmin for example), since it applies to all of the studies.
However, if I store it separately from other roles (in the users table), it seems to be somewhat illogical and can lead to unwanted complexity in the code that handles related logic.
Should I store such attribute in the linking table or in the users table? Why?
some very basic SQL for the tables:
CREATE TABLE `users` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`EMAIL` varchar(100),
PRIMARY KEY (`ID`)
);
CREATE TABLE `studies` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`NAME` varchar(150),
PRIMARY KEY (`ID`)
);
CREATE TABLE `studies_users` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`STUDY_ID` int(10),
`USER_ID` int(10),
`ROLE_ID` tinyint(3),
PRIMARY KEY (`ID`)
);

If you stick your DB design to the real world, 'superadmin' is an attribute of the user, functionally determined by the user only, and as such should be in table user. Yes, this will add some complexity to the queries but will spare you headaches when users change from superadmin to 'normal'; you will just need to change a flag and your data will remain consistent at all times.

Since your "superadmin" role is a special role, not like the other roles you describe, you shouldn't feel compelled to store them together in the same table. You may call them both roles but that doesn't mean they're the same thing.
The most straightforward approach would be to have a table storing the primary keys of all users who belong to this superadmin role. Adding a field to the user table means storing additional data (or even worse, NULLs) in every row, even when only a very small minority of your users are superadmins.

Related

Insert Data into multiple tables in MySQL

Consider two tables User and UserDetails
User (UserID,Name,Password)
UserDetails(UserID,FullName, Mobile Number,EMail)
First I will enter details into User table
Then Afterwards I wish to enter details into UserDetails Table with respect to primary key of first table i.e., UserID which is autoincremented.
consider this scenario..
User: (101, abc, xyz), (102,asd,war)
Now i want to store details in second table with respect to Primary key where UserID= 102
How can I accomplish this?
Start over with the design. Here is a start that runs through and doesn't blow up. Do the same for email. Keep data normalized and don't cause unnecessary lookups. When you have a lot of constraints, it is a sign that you care about the quality of your data. Not that you don't without constraints, if they are un-constrainable.
We all read on the internet how we should keep main info in one table and details in another. Nice as a broad brush stroke. But yours does not rise to that level. Yours would have way too many tables. See Note1 at bottom about about Entities. See Note2 at bottom about performance. See any of us with any broad or specific question you may have.
create table user
( userId int auto_increment primary key,
fullName varchar(100) not null
-- other columns
);
create table phoneType
( phoneType int auto_increment primary key, -- here is the code
long_description varchar(100) not null
-- other columns
);
create table userPhone
( id int auto_increment primary key,
userId int not null,
phone varchar(20) not null,
phoneType int not null,
-- other columns
CONSTRAINT fk_up_2_user FOREIGN KEY (userId) REFERENCES user(userId),
CONSTRAINT fk_up_2_phoneType FOREIGN KEY (phoneType) REFERENCES phoneType(phoneType)
);
Note1:
I suspect that your second table as you call it is really a third table, as you try to bring in missing information that really belongs in the Entity.
Entities
Many have come before you crafting our ideas as we slug it out in design. Many bad choices have been made and by yours truly. A good read is third normal form (3NF) for data normalization techniques.
Note2:
Performance. Performance needs to be measured both in real-time user and in developer problem solving of data that has run amok. Many developers spend significant time doing data patches for schemas that did not enforce data integrity. So factor that into performance, because those hours add up in those split seconds of User Experience (UX).
You can try this:-
INSERT INTO userDetails
(SELECT UserID, Name FROM User WHERE USerID= 102), 'Mob_No', EMail;

Using databases and tables (MySQL)

On my website, customers have the option of creating an event with various items (that have attributes like seller, color, etc.).
Should I have ONE database and a new table for each event? I don't know of another way to program this and splitting every customer/event into a new database seems like a bad solution, but I'm new to databases and don't know if that's stupid.
I assume that I'd have a TABLE with user IDs, a TABLE for each event, and a TABLE that links the user to the event(s) he/she created. Is this the optimal way to do this? All in one database?
Thanks!
You should have a one-to-many relationship between a user table, and an event table. The event table should have the user ID as a foreign key.
CREATE TABLE user (
id int UNSIGNED AUTO_INCREMENT NOT NULL,
name varchar(50) NOT NULL,
last_modified timestamp NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY (name)
);
CREATE TABLE event (
id int UNSIGNED AUTO_INCREMENT NOT NULL,
user_id int UNSIGNED NOT NULL,
name varchar(50) NOT NULL,
description varchar(500) NOT NULL,
last_modified timestamp NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES user.id ON UPDATE CASCADE ON DELETE CASCADE
);
So then, you have your users, and when you add an event, you just assign the user_id to whatever user the event is for. Hopefully that gives you something to build from.
If you have a small number of event types, and the event types are very different in nature (different properties) then you may create a different table for each event type.
However usually you will create one database with one table for all the events, with a column for event type or code (if needed). You also don't need to create a table that contain all the event types, your code can contain them. You table should contain only the actual events that were fired.

table creating regarding social networking post

I want to design structure for posting image,video,url, audio,text etc for users.
I have create
CREATE TABLE users (
userID INT NOT NULL AUTO_INCREMENT,
firstName VARCHAR(50),
lastName VARCHAR(50),
password CHAR(32),
PRIMARY KEY (userID)
);
CREATE TABLE post(
postID INT NOT NULL AUTO_INCREMENT,
message VARCHAR(200)
PRIMARY KEY (postID));
MY question is should I design different tables for storing image,video,url etc
like
Image table
CREATE TABLE post_image(
imageID INT NOT NULL AUTO_INCREMENT,
imgPATH VARCHAR(200)
PRIMARY KEY (imageID));
same of video,link etc.
Or it can be done only in single table.
I've seen this done two ways.
You create a generic "asset" table that stores all possible things that could be attached to a post. Videos, images, URLs, etc.
Create a separate table for each asset type. A post_image table, post_comment, post_video, etc.
I prefer (2) only because the asset types will be pretty different from each other. Think of storing information about a video. You have the video duration, whether or not to auto-play, etc. Images will never have those properties.
So even though you could put all those things into one table, I would strongly recommend not to do it.

Advice needed on primary key selection

I'm building a database for what is soon to be my version of a social networking site. Now, I'd like to store friend relations, sort of like facebook does. I should mention that I'm using MySQL for this.
So i'm thinking of doing something like this:
UserFriends
(
UserFriendID SOME_DATA_TYPE NOT NULL AUTO_INCREMENT PRIMARY KEY,
UserID BIGINT(20) UNSIGNED NOT NULL,
FriendID BIGINT(20) UNSIGNED NOT NULL -- This is basically the same as UserID
)Engine=InnoDB;
Now, I'm looking for some type of data type to use for the primary key for this table as I expect that there will be a ton of records and I'd like some type of indexing to speed up any types of look-up that I might do on the records. Such as a friend suggestion feature etc.
I'm open to suggestions. Another option, in my opinion, but much more difficult to manage is to dynamically create a separate table for each user and store their friends in them, however this would be sort of a nightmare to manage code-wise.
If you do something like this
create table UserFriends
(
UserFriendID SOME_DATA_TYPE NOT NULL AUTO_INCREMENT PRIMARY KEY,
UserID BIGINT(20) UNSIGNED NOT NULL,
FriendID BIGINT(20) UNSIGNED NOT NULL -- This is basically the same as UserID
) Engine=InnoDB;
then you'll probably end up with data that looks like this.
UserFriendID UserID FriendID
--
1 100 201
2 100 201
3 201 100
The problem with that should be obvious.
If you don't need to know who friended whom, then something like this would make more sense. (Standard SQL, not MySQL.)
create table UserFriends (
UserID BIGINT(20) UNSIGNED NOT NULL,
FriendID BIGINT(20) UNSIGNED NOT NULL,
primary key (UserID, FriendID),
check (UserID < FriendID),
foreign key (UserID) references users (UserID),
foreign key FriendID references users (UserID)
);
The primary key constraint guarantees that you don't have multiple identical rows for a single "friendship". The check() constraint guarantees that you don't have two rows, differing only in the order of the id numbers, for a single "friendship".
But because MySQL doesn't enforce check() constraints, you'll have to write a trigger to make sure that UserID is less than FriendID.
use the same pattern BIGINT(20)
avoid a table per user like the plague :)
Just use INT. There are lots of methods to optimize performance, choosing an unusual primary key data type is not one of them.
Don't create one table per user. If you really have a lot of users, you can split them by some shard key later when you know where your bottlenecks are.
If you are expecting to have enough records to fill INT data type, MySQL is not the right solution, especially for recommendations, multi level friend-of-friend-of-friend etc. It might be more suited for one of Graph databases out there. Neo4j is a good example, designed specifically for social networks. http://neo4j.org check it out, might be a good alternative. You don't have to get rid of mysql, it most likely will be a hybrid approach.

mysql - referencing one foreign key to multiple possible primary keys

I'd like to set up the following database scenario:
CREATE TABLE IF NOT EXISTS `points` (
`po_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`po_north` INT,
`po_east` INT,
PRIMARY KEY (`po_id`),
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `lines`(
`li_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`li_from` INT NOT NULL,
`li_to` INT NOT NULL,
PRIMARY KEY (`li_id`),
FOREIGN KEY (`li_from`) REFERENCES points(`po_id`),
FOREIGN KEY (`li_to`) REFERENCES points(`po_id`),
) ENGINE=InnoDB;
Now I want to set up a third table, that sores some metadata like who created or altered a point or a line:
CREATE TABLE IF NOT EXISTS `metadata` (
`me_type` ENUM('point','line') NOT NULL,
`me_type_id` INT UNSIGNED NOT NULL,
`me_permissions` VARCHAR(255) NOT NULL,
`me_created_by` INT UNSIGNED NOT NULL,
`me_created_on` DATETIME NOT NULL,
`me_last_modified_by` INT UNSIGNED NOT NULL,
`me_last_modified_by` DATETIME NOT NULL,
) ENGINE=InnoDB;
My first approach was to set an ENUM with two types (points and lines). But the problem is still, that I cannot properly reference a foreign key to one of the tables. Is there any recommended solution for such problem in MySQL?
BTW:
The fields for me_created_by and me_last_modified_by shall reference to a table storing some user data.
Your case appears to be yet another instance of the design pattern known as "generalization specialization" or perhaps "table design for class inheritance".
If you think of points and lines as classes of objects, they are both subclasses of some more general class of objects. I'm not sure what name to give the superclass in this case. Here's one of several previous questions that address the same issue.
Extending classes in the database
Fowler gives an extensive treatment of the subject. Your case has an added wrinkle, because you are dealing with metadata. But that need not alter the design. You need a third table, which I'll call "Items" for lack of a better term. The key, "it_id" would be assigned an auto number, and you would add an item every time you add either a point or a line. The two columns "po_id" and "li_id" would not be assigned an auto number. Instead they would be foreign keys, referencing "it_id" in the Items table.
The references to points or lines in the metadata table would then be references to "items" and you could use that information to find information about points or lines as the case may be.
How helpful this is depends on what you are trying to do with the metadata.
Your tables points and lines should contain a foreign key to metadata – not the other way around. Doing so will save you from defining any more complicated table setups. Using this approach, a single metadata-entry could be re-used several times for many different points or lines. This isn't even MySQL specific but a general, normalized database structure.
you can do this using a trigger, you need to trigger an event that can create reference key for either point or line before you insert a record based on respective tables