SQL Table Relationships - Trying to Avoid Cyclical Relationships - mysql

I'm trying to manage table relationships in my database, but every option I mock up ends up creating cyclical relationships, which seem to be a big no-no. Here is my setup:
I have the Group table:
+----+--------+
| id | name |
+----+--------+
| 1 | group1 |
| 2 | group2 |
+----+--------+
I also have a UserToGroup table giving users access (with varying permission level) to groups, with FKs pointing to my Group (many-to-one) and to my User table (many-to-one):
+----+----------+---------+---------------+
| id | group_id | user_id | permission_id |
+----+----------+---------+---------------+
| 1 | 1 | 1 | 2 |
| 2 | 1 | 2 | 3 |
| 3 | 2 | 1 | 2 |
+----+----------+---------+---------------+
Where I get stuck is that I want to add an owner flag on each instance of the Group table, where creating a FK constraint would block SQL from removing the UserToGroup instance of a group's owner (ultimately the owner of a group cannot lose permission access to its group.
Functionally, owner permission is completely independent from the permissions granted to users (as the owner would have access to certain management pages, while permission access grants various levels of read/write), and I want to always maintain a required UserToGroup instance in the database for the group's owner, stopping the database (through FK constraints) from the possibility of removing the owner from the UserToGroup table, where he manages all users for a given group.
Initially I had Group.owner_id pointing to the given User, but that only create a FK constraint for when the user is deleted.
I have also tried creating the following variations to my database, but they create cyclical relationships:
Where I created a FK in my Group table pointing to a UserToGroup instance labelling it as the owner's instance:
+----+--------+---------------------+
| id | name | owner_user_to_group |
+----+--------+---------------------+
| 1 | group1 | 2 |
| 2 | group2 | 3 |
+----+--------+---------------------+
Inversly, where I created an owner table that would manage the owner check between the Group and UserToGroup tables:
+----+----------+------------------+
| id | group_id | user_to_group_id |
+----+----------+------------------+
| 1 | 1 | 2 |
| 2 | 2 | 3 |
+----+----------+------------------+
But in both cases it creates a cyclical relationship with the Group table, where both cannot be created without each other.
Is there a way I can manage both owner and permissions separately for Group instances, but also create a logical relationship between both in my database so that I can use the FK constraints to avoid SQL from deleting the UserToGroup instance of the Group's owner?

I might have misunderstood but are you looking for this?
If not, try to explain more simply what you need exactly and I'll try again.

Related

How to create users database table for different user access levels

I have an issue about creating database table for user to login in different level access of the system.
I have 3 user roles "ENUM(master_admin, admin_country, admin_city )".
If the master_admin logged in will have access to the whole system,
but if admin_city logged in will have access to his country only with countryID,
and if admin_city logged in will have access to his city data only with cityID
The problem is on creating users table that will save info of different
administrators so they can have access to their related part of the system.
So later when other admin created to cover other parts of the system it will be easily to set them using the same users table.
I tried this:
users table
+--------+-----------+-------------+
| userID | countryID | user_role| |
+--------+-----------+-------------+
| 1 | 23 | master |
+--------+-----------+-------------+
countries table
+-----------+-------------+
| countryID | countryName |
+-----------+-------------+
| 23 | US |
+-----------+-------------+
coutrries table
+-----------+-------------+-------------+
| cityID | countryID | cityName |
+-----------+-------------+-------------+
| 2 | 23 | New York |
+-----------+-------------+-------------+
How can I set my users table for this problem.
Split the users table
users table
+--------+-----------+-----------------+
| userID | username | email |
+--------+-----------+-----------------+
| 1 | adm | master#master |
+--------+-----------+-----------------+
users_Role table
+--------+-----------+------------+-------------+
| userID | countryID | cityID | roleID |
+--------+-----------+------------+-------------+
| 1 | 23 | NULL | 1 |
+--------+-----------+------------+-------------+
| 1 | 22 | NULL | 2 |
+--------+-----------+------------+-------------+
| 1 | NULL | 2 | 3 |
+--------+-----------+------------+-------------+
role table
+-----------+-----------------+
| roleID | roleName |
+-----------+-----------------+
| 1 | Master |
+-----------+-----------------+
| 2 | COUNTRYMASTER |
+-----------+-----------------+
| 3 | CityMaster |
+-----------+-----------------+
OF course you could make a City/Countryid column, as the role defines what type of id is saved.
So can give or remove for every user individual rigst, per country and/or city.
User_role has redundant indormation so another rolentable is necessary for nomalization
You didn't really try all that much, which means your question is reasonable vague. Whenever you design a system with varying levels of access you need to make very sure that access can't be accidentally granted. Even a bug shouldn't make this possible.
A bad way to do this would be to create a cityId in the users table. If there's a number there, say 2, the user has only access to data of New York, if it is 3 only Washington, etc. If the value is zero the user has access to all cities. Choosing zero seems to make sense here, but it is dangerous, because a bug in setting the cityId could set it to zero and give access that shouldn't be granted.
The normal way to do this is to make a separate table which very explicitly grants access. You could call this table permission. Each user can have multiple permissions. You could define a level in it: 'master', 'country' and 'city'. This tells you what kind of access someone has. Other fields could specify exactly which country or city.
Whenever the user accesses a resource you have to check it against the permissions an user has. access is only granted when the answer is positive. You have to write your software in such a way, that forgetting to check the permission, would break the functionality of the software.
I would also log every access, and every change made to the permission table. It might surprise you how often you will have to play detective and find out exactly who did what when.
No matter what you do, this will never be as secure as it can be. There's always a change an user can access something they shouldn't. It could be due to a bug, or a mistake by an administrator. The only way to have real security is to actually put cities and countries in different databases, and let users only exist in the database to which they are allowed to have access. Security and practicality often are enemies.

Good practice on saving properties in relational database

Let's assume I have two types of users in my system.
Those who can program and those who cannot.
I need to save both types of users in the same table.
The users who can program have lots properties different to those who can't, defined in another table.
What's either advantages of the following solutions and are there any better solutions?
Solution 1
One table containing a column with the correspondig property.
Table `users`:
----------------------------
| id | name | can_program |
----------------------------
| 1 | Karl | 1 |
| 2 | Ally | 0 |
| 3 | Blake | 1 |
----------------------------
Solution 2
Two tables related to each other via primary key and foreign key.
One of the tables containing the users and the other table only containing the id of those who can program.
Table users:
--------------
| id | name |
--------------
| 1 | Karl |
| 2 | Ally |
| 3 | Blake |
--------------
Table can_program:
---------------------
| id | can_program |
---------------------
| 1 | 1 |
| 3 | 1 |
---------------------
You have a 1-1 relationship between a user and the property that allows him to program. I would recommend storing this information as an additional column in table users. Creating an additional table will basically results in an additional storage structure with a 1-1 relationship to the original table.
Why not just have some kind of programmer_profiles table that the users table has a one-to-many relationship with?
If there's an associated record in programmer_profiles then they can program, otherwise it's presumed they can't.
This is more flexible since you can add in other x_profiles tables that provide different properties even if some of these have the same names.

MySQL link two tables together implicitly

Suppose we have two tables
A table called people with people linked to a bank account balances
| id | name | account_id |
--------------------------
| 1 | bob | 11 |
--------------------------
| 2 | sam | 22
A table called accounts with bank account balances
| id | value |
--------------
| 11 | 200 |
--------------
| 22 | 500 |
In order to link the two tables you can do
SELECT a.value as account_balance
FROM people p
WHERE p.name="bob"
LEFT JOIN accounts a ON p.account_id = a.id`
This would return
id => 1
name => bob
account_balance => 200
That's cool - but I am wondering if there is a more implicit way to do this via SQL linkage (foreign keys or otherwise). Can we in MySQL add links in some other way so that when we do a SELECT, it already knows to return value instead of **account_id **?
I'm asking this because I am creating a system where my users can create lookup tables and link them to other tables - but it must be do-able without any programming. The only other way I can think of is to set the name of account_id for example to accounts.value and treat that as a foreign key when doing a SELECT.
I would have to get the column structure and analyze and then determine that there is a foreign key and then return the appropriate foreign column by looking at the column name.

How to create a table for a user in a Database

I am creating an mobile application. In this app, I have created a Login and Register activity. I have also created a online Database using AWS(Amazon Web Service) to store all the login information of the user upon registering.
In my database, i have a table called 'users'. This table holds the following fields "fname","lname","username","password". This part works and successfully stores data from my phone to the database.
for example,
| fname | lname | username | password |
| ------ | ------ | -------- | -------- |
| john | doe | jhon123 | 1234 |
Inside the app, I have an option where the user may click on "Start Log", which will record a start and end values on a seekBar.
How can i create a table under a user who is logged in.
(Essentially, i want to be able to create multiple tables under a user.)
for example,
This table should be under the user "john123":
| servo | Start | End |
| ------ | ------ | --- |
| 1 | 21 | 30 |
| 2 | 30 | 11 |
| 3 | 50 | 41 |
| 4 | 0 | 15 |
I know its a confusing question, but
i am essentially just trying to have multiple tables linked to a user.
As to:
How to create a table for a user in a Database
Here are some GUI tools you might find useful:
MySQL - MySQL Workbench
PostgreSQL - PG Admin
As for creating a separate table for each user, refer to #Polymath's answer. There is no benefit in creating separate tables for each user (you might as well use a json file).
What you should do is create a logs table that has a user_id attribute referencing the id in the users table.
-------------------------------------------------------
| id | fname | lname | username | password |
| -- | ------ | ------ | -------- | ------------------- |
| 1 | john | doe | jhon123 | encrypted(password) |
-------------------------------------------------------
|______
|
V
---------------------------------------
| id | user_id | servo_id | start | end |
| -- | ------- | -------- | ----- | --- |
| 1 | 1 | 1 | 21 | 30 |
| 2 | 1 | 2 | 30 | 11 |
---------------------------------------
You should also look into database normalization as your "john123" table is not in 3NF. The servo should be decomposed out of logs table if it will be logged by multiple users or multiple times (which I'm guessing is the case for you).
In reading this I wonder if your design is right. It sounds like you are trying to create a table for each user. I also wonder how scalable it is to have a unique table per user. if you scale to millions of users you will have millions of tables to manage and will probably need a separate index table to find the right table for the user. Why a table for each? Why not a single table with the UserID as a use key value. You can extract the data just by filtering on the UserID.
Select * FROM UsersData ORDER BY DateTime WHERE User == UserID
However I will leave that for you to ponder.
You mentioned that this is a Mobile App. I think what you need to do is look at AWS Federated access and Cognito which will allow you to Identify a user using federate Identities. Pass the User unique Id , plus a temporary (one use) credentials linked to an access Role. Combined this way, you can scale to millions of users with full authentication without managing millions of accounts.
RL

One to one relationship for same relationship to different tables

I creating a database in which I have an artefact that can be associated with either a project, production or performance. I will call the relationship 'comes_from'. This relationship can be a project or a more specific version of a project such as a production or performance.
I don't want to have separate foreign keys on my artefact for each possible value of the 'comes_from' relationship as it feels wrong to have multiple attributes for the same relationship. The only way I can think of doing this is having a separate table that stores the comes_from relationship containing the id of the referenced project or more specific version along with the table the item is located in.
artefact table
+-------------+------------+
| artefact_id | comes_from | -- Foreign key to comes_from
+-------------+------------+
| 1 | 7 |
| 2 | 8 |
+-------------+------------+
comes_from table
+---------------+-----------------+---------------------------------+
| comes_from_id | comes_from (FK) | comes_from_table (FK table) |
+---------------+-----------------+---------------------------------+
| 7 | 19 | project |
| 8 | 13 | performance |
| 9 | 21 | production |
+---------------+-----------------+---------------------------------+
project table
+-------------+
| project_id |
+-------------+
| 19 |
| 20 |
+-------------+
performance table
+-----------------+
| performance_id |
+-----------------+
| 13 |
| 14 |
+-----------------+
production table
+---------------+
| production_id |
+---------------+
| 21 |
| 22 |
+---------------+
Is there a better way to do this as I am not sure I can even resolve this relationship in a SQL query and it may cause issues when I use Doctrine as an ORM on top of this database.
Your solution is good, the "comes_from_table" column could be a simple VARCHAR or INT indexed field acting as a discriminator field. However, I would remove the "comes_from" column from the "artefact" table and the "comes_from_id" column and use directly the "artefact_id" column to reference artefacts in the relationship table.
Regarding Doctrine there shouldn't be any problem, I did something similar in the past using Symfony2 and Doctrine2 for an entity called Tags where a Tag could either belong to a contact or to a contact spouse. I also created a function in the repository file where I could pass the "tag_type" as a parameter so that I could get either the contact or the contact spouse tags.