I'm building a website with a large number of categories, each with its own specific form fields. Because there are so many categories, I wanted to store those form fields in a database.
The categories are stored in a category table:
id | name
-------------
1 | Car info
The fields for that category are stored in a category_field table:
id | fk_id_category | type | label
-------------------------------------------------------------
1 | 1 | text | Your name
2 | 1 | radio | What type of car do your drive?
If a category_field has some predefined options from which the user can choose then these are stored in a category_field_option table:
id | fk_id_category_field | label
-----------------------------------------
1 | 2 | 'Convertible'
2 | 2 | 'Truck'
3 | 2 | 'Minivan'
Now, when a user fills out a form we want to save a reference to this in a form_entry table:
id | fk_id_user | fk_id_category
--------------------------------
1 | 1 | 1
The details of that form entry are saved in a form_entry_details table. However:
If the category_field.type is text we should just save the answer as string
id | fk_id_form_entry | fk_id_category_field | [answer]
-------------------------------------------------------
1 | 1 | 1 | John Doe
If the category_field.type is radio, I want to save a foreign key to the category_field_option
id | fk_id_form_entry | fk_id_category_field | [fk_id_category_field_option]
--------------------------------------------------------------------------
2 | 1 | 2 | 2
How can I solve this? I know I could just store the fk_id_category_field_option as a string, but I need it to actually reference to the category_field_option table since I'm using an ORM (Doctrine 1.2.4).
You can't because the whole idea of foreign keys is to prevent this sort of situation. You either store it as one field without an enforce foreign key or you create two columns, one for the foreign key id (perhaps a default value that relates to 'user defined') and another that takes the user defined info and, probably, defaults to null.
Related
I've been looking around but cannot seem to find a simple solution to this. I've got a simple Access database with a few tables, and I'd like to create a new column that contains a value in this format <REFERENCE ID> - <LETTER>. The reference ID can be directly extracted from a column (column A in example), but the letter needs to change based on the value of a different column. Is there any way to do this without nested IF conditions? Something like a key-value mapping table where I can specify that the LETTER (in the above format) should be be looked up like this:
Lookup table:
| Key |Val|
|---------|---|
| Key 1 | A |
| Key 2 | B |
| Key 3 | C |
| Key 4 | D |
Original reference ID table with associated keys:
| Reference ID | Keys |
|--------------|-------|
| 1000 | Key 1 |
| 1001 | Key 3 |
| 1002 | Key 4 |
| 1003 | Key 1 |
| 1004 | Key 2 |
New column (the one I'd like to create based off of the answer to the question):
| New column |
|--------------|
| 1000 - A |
| 1001 - C |
| 1002 - D |
| 1003 - A |
| 1004 - B |
As you can see, in this case, values are string literals. Keys are picked from a column with data validated fields.
Create a query that pulls in the values.
So,
SELECT [Reference ID], [Keys], [Val] FROM FirstTable
LEFT JOIN SecondTable ON SecondTable.Key = FirstTable.Keys
So, now use the query in place of the table. It will show all the columns, and pull in and translate the key value out to what you want.
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.
I'm trying to figure out the best way to update one of two fields in a table. I have a personrelationship table and it links two people and I would like to have each person be able to set the relationship type on their end.
PersonRelationship Table
id int
user1_id int
user2_id int
user1_reltype /* boss, manager, etc */
user2_reltype
Depending on whether the current user is either user1_id or user2_id in the table, I need to update the user_reltype accordingly. So basically if current userid is in the user1_id field then update user1_reltype otherwise update the user2_reltype.
Since you want each user to be able to independently manage their half of the relationship, you can simplify your table structure
--------------------------------------
| initiator_id | reltype | target_id |
When a person with ID 5 (the 'initiator') marks person with ID 9 (the 'target') as a friend, the table will contain:
---------------------------------------
| initiator_id | reltype | target_id |
+--------------+----------+-----------+
| 5 | 'friend' | 9 |
If person 9 later initiates a 'boss' connection with person 5, the entry can be created without interfering with the row previously created by person 5:
--------------------------------------
| initiator_id | reltype | target_id |
+--------------+---------+_----------+
| 9 | 'boss' | 5 |
This approach will make your table easy to read and your queries easy to write.
Extra:
If you do not already have it, consider creating another table to track relationship types ('reltype'):
-----------------
| id | type |
+----+----------+
| 1 | 'friend' |
| 2 | 'boss' |
and replace the string reltype's in the relationship table with foreign keys.
---------------------------------------
| initiator_id | reltype | target_id |
+--------------+----------+-----------+
| 5 | 1 | 9 |
| 9 | 2 | 5 |
I don't get it I have two foreign keys identically set and two belongsTo() functions but one of them doesn't work right, instead of returning an array it just returns a string value from database.
Here are the tables that I have in database.
Table pages
-----------------------------------------------------
| id | author | title | content | status |
-----------------------------------------------------
| 1 | 1 | page one title | page text | 1 |
-----------------------------------------------------
| 2 | 1 | page one title | page text | 2 |
-----------------------------------------------------
Table users
----------------------------------------------
| id | username | email | role |
----------------------------------------------
| 1 | darth | darth#deathstar.dot | 1 |
----------------------------------------------
Table page_statuses
--------------------------
| id | name | value |
--------------------------
| 1 | Published | 1 |
--------------------------
| 2 | Draft | 2 |
--------------------------
| 3 | Review | 3 |
--------------------------
So the author and status fields from pages table are foreign keys of tables users and table page_statuses.
Both fields, author and status from pages are integers and unsigned, and also indexes. When i check relations in phpmyadmin I get this on pages table:
----------------------------------------------------------------------
| Column | Foreign key constraint (INNODB) | Keyname |
----------------------------------------------------------------------
| author | `laravell`.`users`.`id` | pages_author_foreign |
----------------------------------------------------------------------
| status | `laravell`.`page_statuses`.`value` | pages_status_foreign |
----------------------------------------------------------------------
When I input some data in database on my pages table in author and status fields i can click on numbers and it will lead me to proper data (in phpmyadmin). For example if I click on author number it will redirect me to users table and show the row of that author, so that works.
And now i have set the models
models/
Page.php
PageStatus.php
User.php
And finally i need to set relations.
Under Page.php i have
public function author() {
return $this->belongsTo('User', 'author', 'id');
}
public function pagestatus() {
return $this->belongsTo('PageStatus', 'status', 'value');
}
So everything is set right and everything should be working but something is not.
When I die & dump the author returns just a string while pagestatus returns and array of that row. The output is
----------------------------------------------
| author | status |
----------------------------------------------
| 1 | {"id":2,"name":"Draft","value":2} |
----------------------------------------------
So the status returns correct and author doesn't returns correct.
You can't name the relationship the same as the name of your foreign key column!
Changing either one should work, however I suggest you change the foreign key columns to author_id. Then you also don't need to specify the foreign key column in your relation since you're using the conventional names.
I have a table which only contains id and a field whose data is a list of data. e.g.
--------------
| id | data |
| 1 | a,b,c,d|
| 2 | a,b,k,m|
---------------
I guess it's not a good design that put a list data in a field, so I want to know how can I redesign it?
As per me you need two tables i.e. Master and Transaction tables only when some details are gonna be same for every records and some are gonna be changing. In your case if there are not any other thing related to your id field is gonna be same you can carry on with one table and with following structure.
--------------
| id | data |
| 1 | a |
| 1 | b |
| 1 | c |
| 1 | d |
| 2 | a |
| 2 | b |
| 2 | k |
| 2 | m |
---------------
BUT if there are any other things related to the id fields that is gonna be same for same id records you will have to use two tables.
like following case. there are 3 fields id, name and data.
and you current table looks something like
--------------------------
| id | name | data |
| 1 | testname | a,b,c,d|
| 2 | remy | a,b,c,d|
--------------------------
your new table structure should look like.
table 1 Master
-----------------
| id | name |
| 1 | testname |
| 2 | remy |
-----------------
Table 2 Transaction
--------------
| id | data |
| 1 | a |
| 1 | b |
| 1 | c |
| 1 | d |
| 2 | a |
| 2 | b |
| 2 | k |
| 2 | m |
---------------
For better database management we might need to normalize the data.
Database normalization is the process of organizing the fields and tables of a relational database to minimize redundancy and dependency. Normalization usually involves dividing large tables into smaller (and less redundant) tables and defining relationships between them. The objective is to isolate data so that additions, deletions, and modifications of a field can be made in just one table and then propagated through the rest of the database via the defined relationships. You can find more on below links
3 Normal Forms Database Tutorial
Database normalization
If you have only those two fields in your table then you should have only 1 table as below
id | data
with composite primary key as PRIMARY KEY(id,data) so that there won't be any duplicate data for the respective ID.
The data would be like this
id | data
1 | a
1 | b
1 | c
1 | d
2 | a
2 | b
2 | k
2 | m
You will need another table which can be of the ONE to MANY type.
For e.g. you could have another table datamapping which would have data and ID column where the ID column is a FOREIGN KEY to the ID column of the data table.
So according to your example there would be 4 entries for ID = 1 in the datamapping table.
You will need two tables with a foreign key.
Table 1
id
Table 2
id
datavalue
So the data looks like:
Table 1:
id
1
2
3
Table 2:
id | data
1 | a
1 | b
1 | c
1 | d
2 | a
2 | b
2 | k
2 | m
You are correct, this this is not a good database design. The data field violates the principle of atomicity and therefore the 1NF, which can lead to problems in maintaining and querying the data.
To normalize your design, split the original table in two. There are 2 basic strategies to do it: using non-identifying and using identifying relationship.
NOTE: If you only have id in the parent table, and no other FKs on it, and parent cannot exist without at least one child (i.e. data could not have been empty in the original design), you can dispense with the parent table altogether.