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
Related
Let us say I need to design a database which will host data for multiple companies. Now for security and admin purposes I need to make sure that the data for different companies is properly isolated but I also do not want to start 10 mysql processes for hosting the data for 10 companies on 10 different servers. What are the best ways to do this with the mysql database.
There are several approaches to multi-tenant databases. For discussion, they're usually broken into three categories.
One database per tenant.
Shared database, one schema per
tenant.
Shared database, shared schema. A tenant identifier (tenant key) associates every row with the right tenant.
MSDN has a good article on the pros and cons of each design, and examples of implementations.
Microsoft has apparently taken down the pages I referred to, but they are on on archive.org. Links have been changed to point there.
For reference, this is the original link for the second article
In MySQL I prefer to use a single database for all tenants. I restrict access to the data by using a separate database user for each tenant that only has access to views that only show rows that belong to that tenant.
This can be done by:
Add a tenant_id column to every table
Use a trigger to populate the tenant_id with the current database username on insert
Create a view for each table where tenant_id = current_database_username
Only use the views in your application
Connect to the database using the tenant specific username
I've fully documented this in a blog post:
https://opensource.io/it/mysql-multi-tenant/
The simple way is: for each shared table, add a column says SEGMENT_ID. Assigned proper SEGMENT_ID to each customer. Then create views for each customer base on the SEGMENT_ID, These views will keep data separated from each customers. With this method, information can be shared, make it simple for both operation & development (stored procedure can also be shared) simple.
Assuming you'd run one MySQL database on a single MySQL instance - there are several ways how to distinguish between what's belonging to whom.
Most obvious choice (for me at least) would be creating a composite primary key such as:
CREATE TABLE some_table (
id int unsigned not null auto_increment,
companyId int unsigned not null,
..
..
..,
primary key(id, company_id)
) engine = innodb;
and then distinguishing between companies by changing the companyId part of the primary key.
That way you can have all the data of all the companies in the same table / database and at application level you can control what company is tied to which companyId and determine which data to display for certain company.
If this wasn't what you were looking for - my apologies for misunderstanding your question.
Have you considered creating a different schema for each company?
You should try to define more precisely what you want to achieve, though.
If you want to make sure that an HW failure doesn't compromise data for more than one company, for example, you have to create different instances and run them on different nodes.
If you want to make sure that someone from company A cannot see data that belong to company B you can do that at the application level as per Matthew PK answer, for example
If you want to be sure that someone who manages to compromise the security and run arbitrary SQL against the DB you need something more robust than that, though.
If you want to be able to backup data independently so that you can safely backup Company C on mondays and Company A on sundays and be able to restore just company C then, again, a purely application-based solution won't help.
Given a specific DB User, you could give a user membership to group(s) indicating the companies whose data they are permitted to access.
I presume you're going to have a Companies table, so just create a one-to-many relationship between Companies and MySQLUsers or something similar.
Then, as a condition of all your queries, just match the CompanyID based on the UserID
in my file Generate_multiTanentMysql.php i do all steps with PHP script
https://github.com/ziedtuihri/SaaS_Application
A Solution Design Pattern :
Creating a database user for each tenant
Renaming every table to a different and unique name (e.g. using a prefix ‘someprefix_’)
Adding a text column called ‘id_tenant’ to every table to store the name of the tenant the row belongs to
Creating a trigger for each table to automatically store the current database username to the id_tenant column before inserting a new row
Creating a view for each table with the original table name with all the columns except id_tenant. The view will only return rows where (id_tenant = current_database_username)
Only grant permission to the views (not tables) to each tenant’s database user
Then, the only part of the application that needs to change is the database connection logic. When someone connects to the SaaS, the application would need to:
Connect to the database as that tenant-specific username
I was unable to find a clear answer of how to create an IS_A relationship in Access.
There was the same question here, but without a concise answer:
IS_A relationship primary key validation rules
I have the entity Employee, and two sub-entities Loan_Officer and Branch_Manager. It's a school example of an IS_A relationship really.
I've managed to create A relationship, but there needs to be a constraint that an employee must be either a Loan Officer or a Branch Manager, but can not be both. Now, I can't figure out how to do this, because what ever I do, I can assign the same Employee_ID in both sub-entity tables at once.
I've connected the tables via the PK, as it's shown here:
Now, this table design is just something I've done, in order to be able to connect them via a one-to-one relationship. I had to set the PK of Loan_Officer to "Number" and not "AutoNumber", in order to be able to connect them. The other option is to have a separate PK in Loan_Officer, like "Loan_Officer_ID", and a foreign key, "Employee_ID" in the Loan_Officer table, but the results are again the same (also according to the ER Diagram, the sub-entities don't have a separate PK).
You can't. This is not a feature of the Access database.
You can create CHECK constraints to check for such conditions, but those don't offer features to cascade operations.
See this answer for an example on how to create a CHECK constraint.
There is no such thing as an 'Is A' relationship in databases between tables. This is instead a field in the Employee table or Employee History Table.
The issue of 'can't be both' is a matter of validation logic. Where this validation logic is applied is probably at the form object level (during data entry), not the table level (no data should ever be entered directly into tables by end users).
Look into Access Data Macros . They can be used like SQL triggers firing off when a record is INSERTed, UPDATEed, DELETEed etc.
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.
Here is a question from a newbie. I need to store music data(URL, artist ...) for each user. Should I put all data in one single table with distinct keys for each user. Or maybe it is good idea to have separate tables for each user.
I am making an online player.
Thanks in advance
You will create huge database if you are going to create seprate table for each user, make a table structure that will contain entries of all user in single table....
Create a single table with different user privileges for ex create an
group column table and provide different grouids to different users
e.g. groupid =1 for admin ,2 for normal user etc.
A separate table for each user is not appropriate.
You need one table for the music data (URL, artist, ...).
If the only item you store about users is the name, you can put that into the music data table as well without violating database design principles too much.
As soon as you store additional information about users (e.g. password, e-mail address) you need a second table for the user data and connect the music data to the user data via a foreign key in the music data table (or, in case of a n:m relation, a third table).
If you are looking for further information about database design, keywords are functional dependency and normalization.
Enhanced relationship diagrams may help you in designing your database. It might be worth mapping out your proposed database using these diagrams before you implement them.
This is a good tool to make sure you have a correct database design for you and as previously said below deal with functional dependency and normalization.
This is a good website to help you if you haven't done this before: http://users.csc.calpoly.edu/~jdalbey/205/Lectures/HOWTO-ERD.html
I'm designing a database where two fields have a many-to-one relationship, but I also need a one-to-one relationship between them, and I would like some advice on whether there is a better way to do it than what I've got right now.
My tables are accounts and users. An account can have multiple users, but each account can only and must have one owner. A user can be related to only one account.
I have an account field in the users table, which stores the ID of the account the user is related to. In the accounts table, I have an owner field, which stores the ID of the user who owns the account (i.e. the head admin).
I'm using InnoDB so I can make use of foreign keys. The problem is that I can't create an account or a user without the other being created first (due to the restraints of the foreign keys), so I made owner nullable. Now I can create an account with a null owner, then create the user, and finally set the owner on the account to the user.
Is this acceptable, and is there a better way?
Here are some possible other ways I've come up with, and my thoughts on each:
Have a boolean owner field in the users table. Since every account can only have one owner, this way seems less than ideal because I'd have to ensure only one user per account has the attribute set to true.
Have a third table called owners. This seems like more overhead and more work for no good reason since it's effectively the same as having an owner field in the users table.
How I have it now makes the most sense to me, but it's a little awkward having to set a null owner until I create the user, and then coming back to set it after the fact.
I'd appreciate any input you can give me. Thanks!
This question is similar, but there's no mention of foreign keys: Designing Tables: One to many and one to one at same time?
In general is a bad idea if your schema cannot be sorted topologically, i.e. if you cannot establish an ordering where a table only refers to tables preceding it in the ordering. This sort of "layered" dependency is also a very nice property to have for example for software modules (you have a problem if two modules depends on each other).
In your case you have user that refers to account and account that refers to user so clearly there's no way to find a topological ordering.
One standard solution in this case is to introduce a separate table e.g. "role" where you have three columns: user, account and role. The column role can be either "owner" or "guest".
The fact that you know that (given the current requests) an account must have one and only one owner, or that a user must be listed in one and only one account are not IMO rules that are really pertinent to the domain of "users" and "accounts".
You can implement those rules easily, but structuring your data so that you have no other possibility is IMO a mistake. You should aim to model the domain, not the specific rules... because people will change their mind about what those rules are.
Can you conceive a user with two accounts? Can you conceive an account with multiple owners/admins? I can... and this means that most probably quite soon this will be a request. Structuring the data so that you cannot represent this is looking for troubles.
Also when you have cyclical dependencies in the model your queries will be harder to write.
A very common case is for example to try to represent a hierarchical part list database using just one table with a "parent" field that points to the table itself... much better is having two tables instead, part and component, where component has two references to part and and a quantity.
Your solution is fine.
If you're uncomfortable with the owner column being nullable, you could rely on some magic user record (perhaps with an id of zero) which would be the "system user". So newly created accounts would be owned by user-zero, until their ownership was suitably redefined. That seems smellier than allowing accounts to have a null owner, to me, anyway.
For the current requirement to have only one account per user
alter table UserAccount add constraint un_user_account unique(UserID);
and when the requirement changes to many-to-many, drop the constraint
alter table UserAccount drop constraint un_user_account;
For the one owner only, simply enforce that on the application level.