facebook group alike database design and foreign key - mysql

Here are my requirements:
one user can have many tasks
one group can have many task
one group can have many users
think of it like a facebook group. Invited user in a group can post more than one status. Each user can create many groups.
so it's my database correct? Do I need to specify FK in bridge key?

The design in mysql is correct. If you want to be strict, yes, you do have to enforce integrity using foreign keys in bridge tables.
If a task can belong to only one group you must remove "Task_Group" and add "group_id" into Task table.

Related

Intermediate SQL Table : What for?

I'm managing to create my first complicated J2E Solution and in every tutorial I find some sort of intermediary tables usage, like here :
Tables : User, User_Roles, Roles
While logic would simply add a key to user Table referring to it's role on Roles table, why the usage of that intermediary table ?
I thought it's one or two developpers choice, but everywhere I look for a tutorial, I find this sort of sql schema.
Is it better ? Does it help in something particular ? Speed, security ? Cause from a logic point of view, using one table User and a foreign key to Roles is better.
Thank you
This is a common database relationship modeling called M-N (Many To Many). A User can have many Roles, and a Role can be assigned to many Users, so you need the intermediary table. Here's another example: a Teacher can teach many Classes, and each Class can be taught by many teachers (during different semesters, for example). In this case you need a Teacher-Class intermediary table.
A different kind of relationship is 1-N (one to N). A User can have many Telephones, but each Telephone is owned by a single User. In this case, a User's primary key (PK) is exported as a foreign key (FK) into the Telephones table. No need for an intermediary table.

Are these too many foreign keys?

I'm using MySQL and have been planning out the database structure for a system I'm building out. As I've been going along, I started to wonder if it was acceptable to have a particular foreign key constraint in many different tables. From what I understand, it would be fine, as it makes sense. But I'd like to double check.
For example, I have a users table, and I use the user_id as a foreign key for many tables, sometimes multiple times in one table. For example, I have a one-to-one relationship with a user_settings table, which of course stores the user_id. And then I have a companies table, which alone has a few references to the user_id key. In this case, I have a column that keeps track of the user that created the company in the system (created_by), a column for the main contact (main_contact, who is also a user of the system), and there might be another reference. So that alone, already has the user_id key being used as a foreign key constraint 3-4 times.
Just to add another bit of info, I have a tasks table and that of course needs to reference the user_id to keep track of who it's assigned to, and I also have another column that keeps track of the user that created the task. That would be assigned_to and created_by, respectively.
There are more tables though that reference back to that key. I might be up to 8 references already. I do believe I've designed it properly so far, but based on what I've mentioned, does this sound fine?
Your foreign key usage seems fine to me - after all, you are simply representing logical relationships between your tables.
A user within your system interacts with the data in many ways, and to define these relationships your approach is the correct one.
The key point I think is that under a lot circumstances, you won't always want (or need) to make all the joins that represent your relationships - simply the ones that you need in that context.
As per my undestanding the way you are defining is fine i.e to use a user id to many tables as foreign key.
If your line:: I have a companies table, which alone has a few references to the user_id key doesn't mean that you are using multipe user_id in same table and I know you are not.

Enforcing Constraint Across Multiple One-to-Many Tables

I have the following (highly simplified) database schema:
In summary:
An account has one user (one-to-one)
An account has many projects (one-to-many)
A project has multiple users (one-to-many)
My concern is that the user belongs to the project, and the project belongs to the account, yet using this schema there's no way to guarantee that a user that belongs to an account also belongs to the account that belongs to a project.
My question is this: Is there a way to use MySQL to add a constraint to ensure that the user that belongs to a project also belongs to the account that belongs to the project?
I'm using MySQL 5.1.56.
there's no way to guarantee that a user that belongs to an account also belongs to the account that belongs to a project.
Correct. But this isn't a limitation of MySQL, it is a limitation of your current schema. From what I see, you have created a 1-1 relationship from users > accounts, meaning that a user can only belong to one account under this schema. If your solution for this restrictive relationship is to have duplicate users in the same table, I'm afraid you have a highly denormalized schema, which will be the source of many headaches in the future.
I strongly suggest that you focus on modeling your business entities first (following at least 3NF) before attempting to institute constraints. To start with, it sounds like you need a many-to-many relationship between users and accounts (in order to accommodate the "user that belongs to an account, also needs to belong to another account" requirement)
First off, thank you to Garcia Hurtado for the great feedback and opinions. It's definitely appreciated when someone in the community spends time and energy to provide thoughtful responses.
I ended up using a composite key to resolve this issue. You can see the schema using the following SQL fiddle: http://sqlfiddle.com/#!8/0612b
It doesn't allow you to test it out with INSERT statements so you can simply download and install the database schema to try it out if you'd like.
The easiest test example is to use the following SQL statement:
INSERT INTO project_users (user_id, account_id) VALUES (1, 2)
This will raise the following MySQL error:
#1452 - Cannot add or update a child row: a foreign key constraint fails

Guaranteeing a FK relationship through multiple tables

I'm using MySQL / InnoDB, and using foreign keys to preserve relationships across tables. In the following scenaro (depicted below), a 'manager' is associated with a 'recordLabel', and an 'artist' is also associated with a 'recordLabel'. When an 'album' is created, it is associated with an 'artist' and a 'manager', but both the artist and the manager need to be associated with the same recordLabel. How can I guarantee that relationship with the current table setup, or do I need to redesign the tables?
You cannot achieve this result using pure DRI - Declarative Referential Integrity, or the linking of foreign keys to ensure the schema's referential integrity.
There are 2 ways to solve this problem:
Consider the requirement a database problem, and use a trigger on INSERT and UPDATE to validate the requirements, and fail otherwise.
Consider the nested link a business logic requirement, and implement it in your business logic in PHP/C#/whatever.
As a sidenote, I think the structure is rather strange from a practical perspective - as far as I know an Artist is signed to a RecordLabel, and assigned a Manager separately (either from the label or individually, many artists retain their own manager when switching to another label). Linking the Manager also to the Album only makes sense to record historic managers, enabling you to retrieve who was the manager to the artist when the album was released, but that automatically means your requirement is invalid if the artist switches labels and/or manages later on. I think therefore it is wrong from a practical data view to enforce this link.
What you do is add recordLabel id to the albums table. Then you put two, two column indexes on albumns (recordLabel_id, artist_id) and (recordLabel_id, managers_id).
Because the record_id can only have one value in each row of the albumns table you will have insured integrity.

Model a table that can have a relationship with several tables

I have a table called 'notes', on this table I need to track who made that note, but the problem is that the creator of the note can be a user stored in one of three possible tables:
users
leads
managers
I have though of simply create three fields on 'notes' to represent the three possible relations: note.user, note.lead, note.manager
With this approach I would be forced to create three table joins when requesting the notes to gather the creators information, and I don't think that is the way to go, so I would like to hear your ideas or comments and what would be the best approach on this.
For me personally this smells like a design problem on a totally different part of the schema: Are manageers not users? Do leads carry person information?
With any approach that creates a relation between one column and one of three others, you will need three joins for the select. If you can't rectify the underlying problem, I recommend you use
note_type ENUM('users','leads','managers')
as an additional field and
SELECT
...
IFNULL(users.name(IFNULL(managers.name,leads.name))) AS name
..
FROM notes
LEFT JOIN users ON notes.note_type='users' AND users.id=notes.note_source
LEFT JOIN managers ON notes.note_type='managers' AND managers.id=notes.note_source
LEFT JOIN leads ON notes.note_type='leads' AND leads.id=notes.note_source
...
for the query
I think you need to abstract out the concept of a user id, so that it does not depend on their role. The author of a note could then be specified by the user id.
Users could be assigned roles, and maybe more than one.
The correct way to structure this would be to pull all common data out of users, leads, and managers. Unify this data into a "contact" table. Then if you want to get all notes for a given manager:
managers->contacts->notes
for a lead:
leads->contacts->notes
Notice your original post: "the problem is that the creator of the note can be a user stored in one of three possible tables"
From the structure of your sentence you even admit that all these entities have something in common; they are all users. Why not make the DB reflect this?
you have to model a parent table for the three tables you already have. Define a table that depicts generally user, leads and manager tables. Something like "Person". So you have all of the ids of the three tables and any common attributes on the Person table. And when you must define the relationship you put the foreign id "Person_ID" on the note table. And when you model user, leads and manager tables you also put the primary key as a foreign key to the Person table.
So you would have something like this:
Table users:
Users(
person_id primary key
...(attributes of Users)
foreign key person_id references Person.person_id
)
This model i depict is common to any relational model you have to model using parents and childs