OK, Last post on this subject (I hope). I've been trying to look into normalisation for tables in a website that I've been building and I have to be honest that I've struggled with it, however after my last post it seems that I may have finally grasped it and set my tables properly.
However, one question remains. If I create a table that is seemingly in 3rd normal form, is it acceptable to have areas of white space or empty cells if the data is relevant to that specific table? Let me give you an example:
On a news website I have an Authors_Table
+----+-----------+----------+-----------------+-------------------+---------+----------+---------+
| ID | FIRSTNAME | SURNAME | EMAIL | BIO ( REQUIRED ) | TWITTER | FACEBOOK | WEBSITE |
+----+-----------+----------+-----------------+-------------------+---------+----------+---------+
| 01 | Brian | Griffin | brian#gmail.com | About me... | URL | | URL |
| 02 | Meg | Griffin | meg#gmail.com | About me... | URL | | |
| 03 | Peter | Griffin | peter#gmail.com | About me... | | URL | URL |
| 04 | Glen | Quagmire | glen#gmail.com | About me... | URL | URL | |
+----+-----------+----------+-----------------+-------------------+---------+----------+---------+
This would be used on the article page to give a little details about who has written it, which is very common in newspapers and on modern blogs. Now the last 3 columns Facebook, Twitter, Website are obviously relevant to the Author & therefore to the PK (ID). As you know though, not everyone has either twitter or a wesbite or facebook so the content of these cells is rather flexible so obviously empty cells will occur in some cases.
It was suggested to do it another way so I produced:
Links
+----+-------------------+
| ID | TYPE |
+----+-------------------+
| 01 | Facebook |
| 02 | Twitter |
| 03 | Website |
+----+-------------------+
Author_Links
+----------+--------+------+
| AUTHOR | TYPE | LINK |
+----------+--------+------+
| 01 | 01 | URL |
| 01 | 02 | URL |
| 01 | 03 | URL |
| 02 | 02 | URL |
| 02 | 03 | URL |
| 03 | 01 | URL |
+----------+--------+------+
Now I understand the concept of this however isn't it just as "correct" to have and to use the original table. Updates can be made using a form & php to say:
$update_link_sql = "UPDATE authours SET facebook = ' NEW VALUE ' WHERE id = '$author_id'";
$update_link_res = mysqli_query($con, $update_links_sql);
As for me Authors_Table is correct.
| ID | FIRSTNAME | SURNAME | EMAIL | BIO ( REQUIRED ) | TWITTER | FACEBOOK | WEBSITE |
The only reason to have three tables:
Authors
| ID | FIRSTNAME | SURNAME | EMAIL | BIO ( REQUIRED ) |
Link_types
| ID | TYPE |
Author_links
| AUTHOR_ID | LINK_TYPE_ID | URL |
...is that your authors could have more than one link of specific type (for example two twitter accounts, btw, is it legal?)
If we suppose that any author can have no more than one account of each type - your version with single table is correct.
Either way is acceptable depending on functional requirements.
If you need to dynamically add more url types/fields to profile then use latter.
If there is ever going to be only 3 then former is better.
No need to over-engineer.
Yes, it's "correct" to store "optional" attributes as columns in the entity table. It's just when we have repeated values, e.g. multiple facebook pages for an author, for example, that we'd want to implement the child table. (We don't want to store "repeating" attributes in the entity table.)
As long as there's a restriction in the model, that an attribute will be limited to a single value (a single facebook page, a single twitter, etc.) those attributes can be stored in the entity table. We'd just use a NULL value to indicate that a value is not present.
One benefit of the separate table approach (outlined in your post) is that it would be "easier" to add a new "type" of URL. For example, if in the future we want to store a blogspot URL, or an instagram URL, instead of having to modify the entity table to add new columns, we can simply add rows to the "link_type" table and "author_link" table. That's the big benefit there.
Related
I need to design a db model for a backend module where user can translate page content into multiple languages. The things that will be translated are basic words, phrases, link names, titles, field names, field values. They should also be grouped so i can find them by group name. For example if there is a select field on page with different colors as options then i should be able to select all of them by group name.
So here is what i have at the moment:
lang
+----+---------+
| id | name |
+----+---------+
| 1 | english |
| 2 | german |
+----+---------+
lang_entity
+----+------------+-------------+-------+-------+
| id | module | group | name | order |
+----+------------+-------------+-------+-------+
| 1 | general | | hello | 0 |
| 2 | accounting | colorSelect | one | 1 |
| 3 | accounting | colorSelect | two | 2 |
| 4 | accounting | colorSelect | three | 3 |
+----+------------+-------------+-------+-------+
lang_entity_translation
+----+---------+----------------+-------------+
| id | lang_id | lang_entity_id | translation |
+----+---------+----------------+-------------+
| 1 | 1 | 1 | Hello |
| 2 | 2 | 1 | Guten tag |
| 3 | 1 | 2 | One |
| 4 | 2 | 2 | Ein |
| 5 | 1 | 3 | Two |
| 6 | 2 | 3 | Zwei |
| 7 | 1 | 4 | Three |
| 8 | 2 | 4 | Drei |
+----+---------+----------------+-------------+
So lang table holds different languages.
Table lang_entity has entities that can be translated for different languages.
Module row is just to group them by page modules in the backend translating module. Also this gives me possiblity to have entities with same name for different modules.
Group as mentioned is needed for selects and maybe some other places where multiple values are going to be used. This also gives me an option to allow user to add and order entities in one group.
And table lang_entity_translation holds the translations for each entity in each language.
So my question is are visible flaws in this kind of a design? Would you reccomend something different?
Also a bonus question: I really dont like the lang_entity table name, do you have a better idea of a table name that would hold all the words/phrases that are translated? :)
Edit: similar, but not a duplicate. The linked question is about translating dynamic products and having a seperate table for each translated type. Im talking about translating whole page content, including groups in a single table.
I don't understand the order column of lang_entity, but then I probably don't need to.
The setup looks sane, but make sure you add foreign key constraints from lang_entity_translation to language and lang_entity.
As for naming, I would call the table phrase or translatable.
We had similar situation. This was 7 years before.
We had different column for different language. Like for name we had
Name_Eng,Name_Ger,Name_Spa .We had 7-10 language.
We had common id for name for all language.
Based on the Language selection from UI we passed the language code to Back end In the Stored proc it was appended to the column Name
Example, we will be passing "Eng" if English is selected and we form the column name as Name_Eng and fetch the data. we were using dynamic query.
Is it possible to auto insert a record into the primary table if the record does not exist when adding a foreign key?
For example, assume these tables:
- user(id, name, age)
- topic(id, name)
- post(userId, topicId, text, createdAt, updatedAt)
Now i am pulling posts from some source and saving the records in the post table. But sometimes the data that is being returned contains a userId or a topicId that is not yet in my database. So everytime i would have to check if the user and topic records exist then save if not. Only then my post record would be valid and saved.
I want to be able to save the post even if its related user or topic does not exist, and add an empty row with the in these tables having the ids that have been stored in the post table.
Example:
Current User Table
+----+------+-----+
| id | name | age |
+----+------+-----+
| 15 | Paul | 26 |
+----+------+-----+
| 56 | John | 31 |
+----+------+-----+
current Topic Table
+----+----------+
| id | name |
+----+----------+
| 5 | Business |
+----+----------+
| 12 | General |
+----+----------+
current Post Table:
+--------+---------+----------------+-------------+-------------+
| userId | topicId | text | createdAt | updatedAt |
+--------+---------+----------------+-------------+-------------+
| 15 | 12 | blah blah blah | *timestamp* | *timestamp* |
+--------+---------+----------------+-------------+-------------+
| 56 | 5 | lorem ipsum... | *timestamp* | *timestamp* |
+--------+---------+----------------+-------------+-------------+
So then i fetch post from some sources an get a new 1 This is a new topic posted by a user with id 72 in a topic with id 2. The source only returns the id, and to obtain the rest of the details of the user, i should make another request to their api.
Post Table after:
+--------+---------+---------------------+-------------+-------------+
| userId | topicId | text | createdAt | updatedAt |
+--------+---------+---------------------+-------------+-------------+
| 15 | 12 | blah blah blah | *timestamp* | *timestamp* |
+--------+---------+---------------------+-------------+-------------+
| 56 | 5 | lorem ipsum... | *timestamp* | *timestamp* |
+--------+---------+---------------------+-------------+-------------+
| 72 | 2 | This is a new topic | *timestamp* | *timestamp* |
+--------+---------+---------------------+-------------+-------------+
User Table After:
+----+------+-----+
| id | name | age |
+----+------+-----+
| 15 | Paul | 26 |
+----+------+-----+
| 56 | John | 31 |
+----+------+-----+
| 72 | | |
+----+------+-----+
Topic Table after
+----+------------+
| id | name |
+----+------------+
| 2 | |
+----+------------+
| 5 | Business |
+----+------------+
| 12 | General |
+----+------------+
So now that i have this, i can make my request to their api and look for data for user with id 72 and data for topic with id 2.
People can have strong opinions on this and we can respectfully disagree.
In reference to a comment saying people do this (knowingly loading blank and null junk in tables) all the time as seen in the post Here.
I said:
That reference is a consortium of people out of their minds. Writing a
post saying what people want to hear, putting a lollipop in their
mouths, does not make for a decent answer. In fact, it can be pretty
irresponsible. This OP is doing things in the wrong order. Put stuff
in some staging tables, call the other APIs, get stuff in clean, that
makes me sleep well at night. Referential Integrity has a meaning. We
don't twist it and confuzzle everyone just to please them.
Part of our responsiblity is doing the right thing, in the right order, to keep our data clean and supporting Referential Integrity. And to steer our peers toward the same versus anything contrary. Sort of the Prime Directive.
Recently I have been planning a system that allows a user to customize and add to a web interface. The app could be compared to a quiz creating system. The problem I'm having is how to design a schema that will allow for "variable" numbers of additions to be made to the application.
The first option that I looked into was just creating an object for the additions and then serializing it and putting it in its own column. The content wouldn't be edited often so writing would be minimal, reads however would be very often. (caching could be used to cut down)
The other option was using something other than mysql or postgresql such as cassandra. I've never used other databases before but would be interested in learning how to use them if they would improve the design of the system.
Any input on the subject would be appreciated.
Thank you.
*edit 29/3/14
Some information on the data being changed. For my idea above of using a serialized object, you could say that in the table I would store the name of the quiz, the number of points the quiz is worth and then a column called quiz data that would store the serialized object containing the information on the questions. So overall the object could look like this:
Questions(Array):{
[1](Object):Question{
Field-type(int):1
Field-title(string):"Whats your gender?"
Options(Array):{"Female", "Male"}
}
[2](Object):Question{
Field-type(int):2
Field-title(string):"Whats your name?"
}
}
The structure could vary of course but generally i would be storing integers to determin the type of field in the quiz and then a field to hold the label for the field and the options (if there are any) for that field.
In this scenario I would advise looking at MongoDB.
However if you want to work with MySQL you can think about the entity-attribute-value model in your design. The EAV model allows you to design for entries that contain a variable number of attributes.
edit
Following your update on the datatypes you would like to store, you could map your design as follows:
+-------------------------------------+
| QuizQuestions |
+----+---------+----------------------+
| id | type_id | question_txt |
+----+---------+----------------------+
| 1 | 1 | What's your gender? |
| 2 | 2 | What's your name? |
+----+---------+----------------------+
+-----------------------------------+
| QuestionTypes |
+----+--------------+---------------+
| id | attribute_id | description |
+----+--------------+---------------+
| 1 | 1 | Single select |
| 2 | 2 | Free text |
+----+--------------+---------------+
+----------------------------+
| QuestionValues |
+----+--------------+--------+
| id | question_id | value |
+----+--------------+--------+
| 1 | 1 | Male |
| 2 | 1 | Female |
+----+--------------+--------+
+-------------------------------+
| QuestionResponses |
+----+--------------+-----------+
| id | question_id | response |
+----+--------------+-----------+
| 1 | 1 | 1 |
| 2 | 2 | Fred |
+----+--------------+-----------+
This would then allow you to dynamically add various different questions (QuizQuestions), of different types (QuestionTypes), and then restrict them with different options (QuestionValues) and store those responses (QuestionResponses).
I'm attempting to add Breadcrumbs to my website using a MySQL table, and I'm having difficulty at the moment.
I have a table named 'includes' created that stores information about the category, page, subpage, the title, and the ref (url) of the page. Category, Page, and Subpage are all php parameters passed from the page the user is on
My table is laid out like this:
|----------------------------------------------------------------|
| ID | Category | Page | Subpage | Title | Ref |
|----------------------------------------------------------------|
| 0 | | | | Home | ... |
| 1 | Software | | | Software | ... |
| 2 | Software | Desktop | | Desktop Software | ... |
| 3 | Software | Mobile | | Mobile Software | ... |
| 4 | Software | Desktop | Blah | Blah Blah | ... |
| ...
|----------------------------------------------------------------|
What I'm trying to do is make a query that will return only the required steps back to home for the breadcrumbs.
In other words, if the user is on "example.com/software/desktop/blah", the query will return rows 0,1,2, and 4. Or if I was on /software/mobile, it would only return rows 0,1, and 3.
My current attempts have been things like the following:
SELECT * FROM `includes` WHERE
`category` IS NULL AND `page` IS NULL AND `subpage` IS NULL OR
`category`='$category' AND `page` IS NULL AND `subpage` IS NULL OR
`category`='$category' AND `page`='$page' AND `subpage` IS NULL OR
`category`='$category' AND `page`='$page' AND `subpage`='$subpage'
Which not only don't work, but also seem more complex than it should have to be.
I'm probably overcomplicating this, or possibly just doing an entirely wrong method, which is why I've turned here.
Does anyone have a possible solution to this? Should I be looking at a more complex query? (admittedly, SQL is not my forte) Or should I be looking at a new SQL table, or possibly an entirely different method?
What you have is a hierarchical structure. The data is set up with parent-child relationships. There is a good description on how to work with hierarchical data here: http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/
You can make a self relation table like this
id | parent_it | title | Ref
1 | 0 | Home | ...
2 | 1 | Software | ...
3 | 2 | Desktop | ...
4 | 2 | Mobile | ...
5 | 3 | Blah | ...
So your query should get the last element
SELECT * FROM includes WHERE
tilte = 'Blah'
And then get the parent ID title and so on , like this the table structure will be better from my point of view & experience
OR
Generate your query based on the values you get , with simple loop count the arguments and based on that generate the query string then execute it
I hope this can help :)
i have in one table two fields (title, content) and i inserted some values...:
+--------------------------------------+--------------------------+
| title | content |
+--------------------------------------+--------------------------+
| hello word | this is my first content |
+--------------------------------------+--------------------------+
| smoke Smoking is bad for your health | But i love it |
+--------------------------------------+--------------------------+
if I add a auto_increment field called ID, the previously input values take ID = 0:
+---+--------------------------------------+--------------------------+
|ID | title | content |
+---+--------------------------------------+--------------------------+
| 0 | hello word | this is my first content |
+---+--------------------------------------+--------------------------+
| 0 | smoke Smoking is bad for your health | But i love it |
+---+--------------------------------------+--------------------------+
and i need this:
+---+--------------------------------------+--------------------------+
|ID | title | content |
+---+--------------------------------------+--------------------------+
| 1 | hello word | this is my first content |
+---+--------------------------------------+--------------------------+
| 2 | smoke Smoking is bad for your health | But i love it |
+---+--------------------------------------+--------------------------+
The only way to set correct ID to old values is php+foreach? or i forgot something to do with sql/mysql to takes faster and automatically the correct ID values?
Thanks for help.
Well,now its my time to help you :P.
You puts SQL code in a php page or in phpmyadmin online code editor? Sometimes phpmyadmin online editor fails, try it in your php page and it works fine.
ALTER TABLE MyTable
ADD ID INT IDENTITY