One to one relationship for same relationship to different tables - mysql

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.

Related

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.

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

MySQL - At what point should more than one table be used?

Edit for future viewers: Aside from the accepted answer which helped me I found some really good info here .
I've got a database with a single table for displaying inventory on a website (RVs). It stores the typical info: year, make, model, etc. I originally made it with 6 extra columns for storing "special features", but I don't like having such a hard limit on what options can be listed. Since I've never messed with more than a single table my gut instinct was to just add 24 or so more columns to cover everything, but something in my head told me that there might be a better way. So when do I decide N columns is too many? The data in these columns will commonly not be unique.
(Sorry for crappy diagram)
Current table design:
-----------------------------------------------------------------------
| id | year | make | model | price | ft_1 | ft_2 | ft_3 | ft_4 | ft_5 |
-----------------------------------------------------------------------
| | | | | | | | | | |
-----------------------------------------------------------------------
Possible better design:
table #1
------------------------------------
| id | year | make | model | price |
------------------------------------
| | | | | |
------------------------------------
table #2
---------------------------------------------
| unique_id(?) | feature | unit_ref |
---------------------------------------------
| 0 | "Diesel Pusher" | 2,6,14 |
---------------------------------------------
I feel like a bonus of the second table might be that I could more easily propagate a dropdown containing all the previously entered features to speed up adding new units to inventory.
Is this the right way to go about it, or should I just add more columns and be content?
Thanks.
Believe it or not, your best option would likely be to add a third table.
Since each record in your rvs table can be linked to multiple rows in the features table, and each feature can correspond to multiple rvs, you have a many-to-many relationship which is inherently difficult to maintain in a relational dbms. By adding a third "intersection" table you convert it to a one-to-many-to-one relationship which can be enforced declaratively by the dbms.
Your table structure would then become something like
rvs
------------------------------------
| id | year | make | model | price |
------------------------------------
| | | | | |
------------------------------------
features
--------------------------
| id | feature |
--------------------------
| 1192 | "Diesel Pusher" |
--------------------------
rv_features
----------------------
| rv_id | feature_id |
----------------------
| | |
----------------------
How do you make use of this? Suppose you want to record the fact that the 2016 Travelmore CampMaster has a 25kW diesel generator. You would first add a record to rvs like
--------------------------------------------------
| id | year | make | model | price |
--------------------------------------------------
| 0231 | 2016 | Travelmore | CampMaster | 750000 |
| 2101 | 2016 | Travelmore | Domestant | 650000 |
--------------------------------------------------
(Note the value in the id column is entirely arbitrary; its sole purpose is to serve as the primary key which uniquely identifies the record. It can encode meaningful information, but it must be something that will not change throughout the life of the record it identifies.)
You then add (or already have) the generator in the features table:
--------------------------------
| id | feature |
--------------------------------
| 1192 | Diesel Pusher 450hp |
| 3209 | diesel generator 25kW |
--------------------------------
Finally, you associate the rv to the feature with a record in rv_features:
----------------------
| rv_id | feature_id |
----------------------
| 0231 | 3209 |
| 0231 | 1192 |
| 2101 | 3209 |
----------------------
(I've added a few other records to each table for context.)
Now, to retrieve the features of the 2016 CampMaster, you use the following SQL query:
SELECT r.year, r.make, r.model, f.feature
FROM rvs r, features f, rv_features rf
WHERE r.id = rf.rv_id
AND rv.feature_id = f.id
AND r.id = '2031';
to get
----------------------------------------------------------
| year | make | model | feature |
----------------------------------------------------------
| 2016 | Travelmore | CampMaster | diesel generator 25kW |
| 2016 | Travelmore | CampMaster | Diesel Pusher 450hp |
----------------------------------------------------------
To see the rvs with a 25kW generator, change the query to
SELECT r.year, r.make, r.model, f.feature
FROM rvs r, features f, rv_features rf
WHERE r.id = rf.rv_id
AND rv.feature_id = f.id
AND f.id = '3209';
Sherantha's link to A Quick-Start Tutorial on Relational Database Design actually looks like a good intro to table design and normalization; you might find it useful.
There is a thing calles "third normal form" it says that everything without the unique ids shuld be unique. This means you need to make a table for year, a table for make a table for models etc and a table where you can combine all these ids to one connected dataset.
But this is not always practical, io think the best way to take this is something in between, like tables for entrys that repeat very often, but there dont need to be an extra table for price with unique ids, that would be overkill i think.
Based upon your scenario, if you believe no. of features columns remain same then no need for second table. And in case if there any possibility that features can be increased at any time in future then you should break up your table into two. (RVS & Features). Then create a third table that identify RVS & features as it seems there is many-to-many relationship. So I suggest you to use three tables.
I think it is better for you to be more familiar with relational database design. This is a short but great article I have found earlier.

CRM Releationships MySQL

Our Company is developing a CRM and we came now to the point where we have to decide how we want to handle the releationships. This is an important point because there are going to be tons of them. And changing the structure later would be simply not cool..
I know 3 ways how we could do it:
One releationship table:
The way i would do this is creating one table holding all the releationships.
Table: releationships
+----+-------------+-----------+--------------+------------+
| id | record_type | record_id | belongs_type | belongs_id |
+----+-------------+-----------+--------------+------------+
| 1 | person | 42 | company | 12 |
+----+-------------+-----------+--------------+------------+
| 2 | person | 43 | company | 12 |
+----+-------------+-----------+--------------+------------+
| 3 | note | 23 | company | 12 |
+----+-------------+-----------+--------------+------------+
| 4 | attachment | 13 | company | 12 |
+----+-------------+-----------+--------------+------------+
Multiple releationship tables:
I think this is the way how it for example the SugarCRM does.
Table: company_realationships
+----+-----------+------------+--------+
| id | record_id | has_type | has_id |
+----+-----------+------------+--------+
| 1 | 12 | person | 42 |
+----+-----------+------------+--------+
| 2 | 12 | person | 43 |
+----+-----------+------------+--------+
| 3 | 12 | note | 23 |
+----+-----------+------------+--------+
| 2 | 12 | attachment | 13 |
+----+-----------+------------+--------+
All in the record table:
Table: person
+----+-----------+------------+
| id | name | company_id |
+----+-----------+------------+
| 42 | luke | 12 |
+----+-----------+------------+
| 43 | other guy | 12 |
+----+-----------+------------+
ect.
So my Question is wich is the Best way of handling lots of releationships?
Are there other ways to do it?
What are disadvantages / advantages?
Is there a special way how hightraffic sides handle their releationships?
Thanks for your help guys :)
So my Question is wich is the Best way of handling lots of releationships?
The third one or the variation of it (see below).
Every "M:N" relationship should be represented by its own junction table. OTOH, a "1:N" relationship doesn't need additional table - just a proper foreign key in the table on the side of the "N".
If I understand your description correctly, the third option models a 1:N relationship between company and person. If by any chance you wanted to model a M:N relationship between them, you'd have a junction table: company_person ( company_id, person_id, PK (company_id, person_id) ).
Are there other ways to do it?
Sometimes, inheritance (aka. category, subtype, generalization hierarchy etc.) can be used to lower the number of possible "relatable" combinations. In a nutshell, make a relationship to a parent, then every child inherited from that parent is automatically involved in that relationship.
For an example, take a look at this post.
What are disadvantages / advantages?
Enforcing constraints (including FKs) declaratively is better (less prone to errors and probably more performant) than enforcing them through triggers, which is again better than enforcing them in the client code.
Choose a design that better adheres to that principle. For example, your options 1 and 2 don't allow the DBMS to enforce FKs declaratively.
Is there a special way how hightraffic sides handle their releationships?
Good logical design followed by good physical implementation is the only solid basis for good performance. It's hard to "bolt-on" the performance on top of a bad design.
Perhaps, you'd like to take a look at:
ERwin Methods Guide
Use The Index, Luke!
And when it comes to performance, don't guess! Measure on realistic amounts of data.

How to split CSVs from one column to rows in a new table in MSSQL 2008 R2

Imagine the following (very bad) table design in MSSQL2008R2:
Table "Posts":
| Id (PK, int) | DatasourceId (PK, int) | QuotedPostIds (nvarchar(255)) | [...]
| 1 | 1 | | [...]
| 2 | 1 | 1 | [...]
| 2 | 2 | 1 | [...]
[...]
| 102322 | 2 | 123;45345;4356;76757 | [...]
So, the column QuotedPostIds contains a semicolon-separated list of self-referencing PostIds (Kids, don't do that at home!). Since this design is ugly as a hell, I'd like to extract the values from the QuotedPostIds table to a new n:m relationship table like this:
Desired new table "QuotedPosts":
| QuotingPostId (int) | QuotedPostId (int) | DatasourceId (int) |
| 2 | 1 | 1 |
| 2 | 1 | 2 |
[...]
| 102322 | 123 | 2 |
| 102322 | 45345 | 2 |
| 102322 | 4356 | 2 |
| 102322 | 76757 | 2 |
The primary key for this table could either be a combination of QuotingPostId, QuotedPostId and DatasourceID or an additional artificial key generated by the database.
It is worth noticing that the current Posts table contains about 6,300,000 rows but only about 285,000 of those have a value set in the QuotedPostIds column. Therefore, it might be a good idea to pre-filter those rows. In any case, I'd like to perform the normalization using internal MSSQL functionality only, if possible.
I already read other posts regarding this topic which mostly dealt with split functions but neither could I find out how exactly to create the new table and also copying the appropriate value from the Datasource column, nor how to filter the rows to touch accordingly.
Thank you!
€dit: I thought it through and finally solved the problem using an external C# program instead of internal MSSQL functionality. Since it seems that it could have been done using Mikael Eriksson's suggestion, I will mark his post as an answer.
From comments you say you have a string split function that you you don't know how to use with a table.
The answer is to use cross apply something like this.
select P.Id,
S.Value
from Posts as P
cross apply dbo.Split(';', P.QuotedPostIds) as S