Related
I have to write the conceptual diagram of a DBMS.
I have a very simple, maybe banal question, but I found no answers on the internet.
This DBMS will be used by the secretaries of a school. In this schema there are entities like students, courses, exams and so on.
Can I also add the entity "secretary", even if the secretaries will be the ones who will use the DBMS?
Sure your can. You can, and in fact, you should throw everything on your conceptual design whiteboard that has any relevance to your system. And do some contemplation of where the chips might fall.
Usually you would have a "User" in your system, and that "User" might be a "Secretary" but very quickly you have other "Users", which would include the "Students" and possibly "Managers" and "Advisors".
The whole point about a word as general as "Entity" in an Entity-Relationship Model is that it is general and anything whatsoever of interest to your problem can be an "Entity" in that sense.
An entity is a type of thing to store in your database system.
Each different entity type has an identifying key, and a distinct set of attributes. For example, a user entity might have some identification number, and perhaps attributes for login name, password, creation date, email, real name, etc.
Then you have to ask if a secretary is just one of the users, or is it a distinct entity?
The answer is driven by whether a secretary has unique attributes. Is there some fact about each secretary that needs to be stored in the database, that no other user has?
If not, then perhaps secretary is just an example of a user entity. Maybe it would be helpful to make the user entity have an attribute column to note the type of user (secretary, administrator, faculty, parent, etc.), but not create a separate entity unless the category of secretary needs their own attributes.
so im reading up on database normalization, and it seems like for the most part, a lot of us are already following up to 2NF or even 3NF without realizing it. I wonder why our professor 4 years ago told us thats a topic discussed in masters database course because its "too complicated" lol...sounds straight forward to me really...
anyways, part of this article here, talks about 3NF, and to achieve that, you need to have 2NF and no no transitive functional dependencies.
the example given is this image, but i dont understand...how could a value of a non-key column change a value of another non-key column? if anything, it sounds to me like a glitch in the system if that were to happen...
Consider the table 1. Changing the non-key column Full Name may change Salutation.
That article is terrible. So clearly some people find it difficult to understand normalisation. (Many people struggle with the difference between 3NF vs Boyce-Codd NF, which the article ducks out of explaining.) The article says
Normalization helps produce database systems that are cost-effective and have better security models.
That's not the chief reason for normalising a design. Indeed in the early days of the Relational Model (when disk was expensive, so for example dates had two-digit years), normalisation (i.e. vertical partitioning) was the opposite of cost-effective, and a lot of attention was paid to trade-offs in (partially) denormalised schemas.
The chief reason for normalisation is to avoid duplicating information and/or duplicates getting out of step, called 'update anomalies'. Specifically:
A transitive functional dependency is when changing a non-key column, might cause any of the other non-key columns to change
Is a terrible way to put it. But might mean: when you update one column (Full Name) of one row (Membership Id 3) you need to also update other column(s) (Salutation) of the same or other row(s) (Membership Id 2?); or if you don't, you break the consistency of the data.
The article doesn't tell us what FDs are expected to hold. Does Full Name determine Salutation? Is it possible the Membership ID 3 Robert Phil could qualify as a Doctor and therefore change his Salutation without Member 2 also becoming a Doctor? Then there is no FD from Full Name to Salutation, and what looks like duplicated entry is not.
Presumably what the example is trying to show (I'm not sure, because it's wrong) is that there's a dependency between Full Name and Salutation. Introducing a Salutation Id is so ... stupid, I'm very tempted to say "not even wrong". It has not removed the Transitive Functional Dependency at all.
Normalisation would (assuming there is a FD from Full Name to Salutation):
Put Full Name and Salutation in a separate table, keyed by Full Name -- that represents one of the FDs.
Remove Salutation from the Membership table.
Not introduce a Salutation ID field.
You can recover the original Membership table by joining to the Full Name, Salutation table.
The alleged 3NF form has not removed the Transitive Functional Dependency, and so is not in 3NF. All it has done is replace a Transitive FD from Membership ID to Full Name to Salutation with one from Membership ID to Full Name to Salutation ID. So if Member 3 changes their name from Robert Phil to Roberta Phil, under the initial design Salutation would have to change in step from Mr to Ms; under the alleged 3NF design still the Salutation ID has to change from 1 to 2.
There are other reasons to think that alleged 3NF design is not 3NF. I expect a dependency from Person to Full Name and to Address. There's no column Person, with the consequence there are two Mr Robert Phils. Are they the same person? Then what if they flatted together? The article tries to introduce a composite key {Full Name, Address}, but that won't help; and it's quite common for same-named father and son to live at the same address. We'd have two people with same name at same address. (What if one of them then qualified as a Doctor?)
Normalisation would introduce a Person ID, key to a Person table, with columns Full Name, Salutation, Address. The partitioned Membership table would have columns Membership ID (key), Person ID (Foreign Key references Person).
I have a relational database schema as follows
The primary keys are underlined.
The scenario is I have to manage the bookings for the tennis courts. As you can see from the image, each court belongs to exactly one sport center, each center belongs to exactly one city. Let's forget the staff, player, and booking table because my question does not concern them.
So my professor had a very weird way of implementing this schema in MySQL. He made the CenterName and CourtName (and even PlayerName) unique attributes. CityName is also unique but I think it's justified. What is worth questioning is the way he did it:
Suppose that I have City A which has Center 1 which has Court i. He would store City A_Center 1 in the CenterName field and City A_Center 1_Court i in the CourtName field.
Basically he would chain information from other attributes to make an attribute unique, instead of defining unique conditions on the attribute sets (CenterName, CityID) and (CourtName, CenterID).
The way he justified for his design is that he could use the names instead of the ID numbers when he call stored functions. He also said names should be preferred over IDs, and ID should only be used for filtering (not sure what that is). He said the combining technique above to make names unique "is done all the time in practice". I really doubt that.
Is that true?
We have a J2EE content management and e-commerce system, and in this system – for sake of a simple example – let’s say that we have 100 objects. All of these objects extend the same base class, and all share many of the same fields.
Let’s take two objects as an example: a news item that would be posted on a website, and a product that would be sold on a website. Both of these share common properties:
IDs: id, client ID, parent ID (long)
Flags: deleted, archived, inactive (boolean)
Dates: created, modified, deleted (datetime)
Content: name, description
And of course they have some properties that are different:
News item: author, posting date
Product: price, tax
So (finally) here is my question. Let’s say we have 100 objects in our system, and they all follow this pattern. They have many fields that overlap, and some unique fields. In terms of a relational database, would we be better off with:
Option One: Less Tables, Common Tables
table_id: id, client ID, parent ID (long) (id is the primary key, a GUID for all objects)
table_flag: id, deleted, archived, inactive (boolean)
table_date: id, created, modified, deleted (datetime)
table_content: id, name, description
table_news: id, author, posting date
table_product: id, price, tax
Option Two: More Tables, Common Fields Repeated
table_news: id, client ID, parent ID, deleted, archived, inactive, name, description, author, posting date
table_product: id, client ID, parent ID, deleted, archived, inactive, name, description, price, tax
For full disclosure – I am a developer and not a DBA, and because of that I prefer option one. But there is another team member that prefers option two, and I think he makes valid points.
Option One: Pros and Cons
Pro: Encapsulates common fields into common tables.
Pro: Need to change a common field? Change it in one place.
Pro: Only creates new fields/tables when they are needed.
Pro: Easier to create the queries dynamically, less repetitive code
Con: More joining to create objects (not sure of DB impact on that)
Con: More complex queries to store objects (not sure of DB impact on that)
Con: Common tables will become huge over time
Option Two: Pros and Cons
Pro: Perhaps it is better to distribute the load of all objects across tables?
Pro: Could index the news table on the client ID, and index the product table on the parent ID.
Pro: More readable to human eye: easy to see all the fields for an object in one table.
My Two Cents
For me, I much prefer the elegance of the first option – but maybe that is me trying to force object oriented patterns on a relational database. If all things were equal, I would go with option one UNLESS a DB expert told me that when we have millions of objects in the system, option one is going to create a performance problem.
Apologies for the long winded question. I am not great with DB lingo, so I probably could have summarized this more succinctly if I better understood terms like normalization. I tried to search for answers on this topic, and while I found many that were close (I suspect this is a common DB issue) I could not find any that answered all my questions. I read through this article on normalization:
But I did not totally understand it. On the one hand it was saying that you should remove any redundancies. But on the other hand, it was saying that each attribute should define only one object.
Thanks,
John
You should read Patterns of Enterprise Application Architecture by Martin Fowler. He writes about several options for the scenario you describe:
Single Table Inheritance: One table for all object subtypes. Stores all attributes, setting them NULL where they are inapplicable to the row's object subtype.
Class Table Inheritance: One table for column common to all subtypes, then one table for each subtype to store subtype-specific columns.
Concrete Table Inheritance: One table for each subtype, storing both subtype-specific columns and columns common to all subtypes.
Serialized LOB: One table for all object subtypes. Store common attributes as conventional columns, but combine optional or subtype-specific columns as fields in a BLOB that stores XML or JSON or whatever format you want.
Each one of these designs has pros and cons, so choose a solution depending on the most common way you access your data.
However, notice I use the word subtype above. I would use these designs only if the different object types are subtypes of a common base class. I'm assuming that News item and Product don't actually share a logical base class (besides Object); they are not subtypes of a common superclass.
So for the sake of OO design, I would choose Concrete Table Inheritance. This avoids any inappropriate coupling between these subtypes. There are columns the two tables have in common, but they basically amount to bookkeeping, not anything to do with the function of the class and hence the table.
My friend and I are building a website and having a major disagreement. The core of the site is a database of comments about 'people.' Basically people can enter comment and they can enter the person the comment is about. Then viewers can search the database for words that are in the comment or parts of the person name. It is completely user generated. For example, if someone wants to post a comment on a mispelled version of a person's name, they can, and that's OK. So there may be multiple spellings of different people listed as several different entries (some with middle name, some with nickname, some mispelled, etc.), but this is all OK. We don't care if people make comments about random people or imaginary people.
Anyway, the issue is about how we are structuring the database. Right now it is just one table with the comment ID as the primary key, and then there is a field for the 'person' the comment is about:
comment ID - comment - person
1 - "he is weird" - John Smith
2 - "smelly girl" - Jenny
3 - "gay" - John Smith
4 - "owes me $20" - Jennyyyyyyyyy
Everything is working fine. Using the database, I am able to create pages that list all the 'comments' for a particular 'person.' However, he is obsessed that the database isn't normalized. I read up on normalization and learned that he was wrong. The table IS currently normalized, because the comment ID is unique and dictates the 'comment' and the 'person.' Now he is insistant that 'person' should have it's OWN table because it is a 'thing.' I don't think it is necessary, because even though 'person' really is the bigger container (one 'person' can have many 'comments' about them), the database seems to operate just fine with 'person' being an attribute of the comment ID. I use various PHP calls for different SQL selections to make it magically appear more sophisticated on the output and the different way the user can search and see results, but in reality, the set-up is quite simple. I am now letting users rank comments with thumbs up and thumbs down, and I keep a 'score' as another field on the same table.
I feel that there is currently no need to have a separate table for just unique 'person' entries because the 'persons' don't have their own 'score' or any of their own attributes. Only the comments do. My friend is so insistant that it is necessary for efficiency. Finally I said, "OK, if you want me to create a separate table and let 'person' be it's own field, then what would be the second field? Because if a table has just a single column, it seems pointless. I agree that we may later create a need to give 'person' it's own table, but we can deal with that then." He then said that strings can't be primary keys, and that we would convert the 'persons' in the current table to numbers, and the numbers would be the primary key in the new 'person' table. To me this seems unnecessary and it would make the current table harder to read. He also thinks it will be impossible to create the second table later, and that we need to anticipate now that we might need it for something later.
Who is right?
In my opinion your friend is right.
Person should live in a different table and you should try to normalize. Don't overdo-it, though.
In the long run you may want to do more things with your site, say you want to attach multiple files to a person (ie. pictures) you'll be very thankfull then for the normalization.
Creating a new table for person and using the key of that table in place of the person attribute has nothing to do with normalization. It may be a good idea for other reasons but doing so does not make the database "more normalized" than not doing it. So you are right: as far as normalization is concerned, creating another table is unnecessary.
I would vote for your friend. I like to normalize and plan for the future and even if you never need it, this normalization is so easy to do it literally takes no time. You can create a view that you query in order to make your SQL cleaner and eliminate the need for you to join the tables yourself.
If you have already reached all of your capabilities and have no plans for expansion of capabilities I think you leave it as it is.
If you plan to add more, namely allowing people to have accounts, or anything really, I think it might be smart to separate your data into Person, Comments tables. Its not hard and makes expanding your functionality easier.
You're right.
Person may be a thing in general, but not in your model. If you were going to hassle people into properly identifying the person they're talking about, a Person table would be necessary. For example, if the comments were only about persons already registered in the database.
But here it looks like you have an unstructured data, without identity; and that nothing/nobody is interested in making sure whether "jenny" and "jennyyy" are in fact the same person, not to mentionned "jenny doe", and "my cousin"...
Well, there are two schools of thought. One says, create your data model in the most normalized way possible, then de-normalize if you need more efficiency. The other is basically "do the minimum work necessary for the job, then change it as your requirements change". Also known as YAGNI (You aren't going to need it).
It all depends on where you see this going. If this is all it will be, then your approach is probably fine. If you intend to improve it with new features over time, then your friend is right.
If you never intend to associate the person column with a user or anything else and data apparently needs no consistency or data integrity checks, just why is this in a relational database at all? Wouldn't this be a use case for a nosql database? Or am I missing something?
Normalization is all about functional dependencies (FD's). You need to identify all of the
FD's that exist among the attributes of your data model before it can be fully normalized.
Lets review what you have:
Any given instance of a CommentId functionally determines the Person (FD: CommentId -> Person)
Any given instance of a CommentId functionally determines the Comment (FD: CommentId -> Comment)
Any given instance of a CommentId functionally determines the UserId (FD: CommentId -> UserId)
Any given instance of a CommentId functionally determines the Score (FD: CommentId -> Score)
Everything here is a dependant attribute on CommentId and
CommentId alone. This might lead you to the belief that a relation (table) containing all of, or a subset of, the
above attributes must be normalized.
First thing to ask yourself is why did you create the CommentId attribute anyway? Strictly speaking,
this is a manufactured attribute - it does not relate to anything 'real'. CommentId is
commonly referred to as a surrogate key. A surrogate key is just a made up value that stands in
for a unique value set corresponding to some other group of attributes. So what group of attributes is CommentId
a surrogate for? We can figure that
out by asking the following questions and adding new FD's to the model:
1) Does a Comment have to be unique? If so the FD: Comment -> CommentId must be true.
2) Can the same Comment be made multiple times as long as it is about a different Person? If so, then
FD: Person + Comment -> CommentId must be true and the FD in 1 above is false.
3) Can the same Comment be made multiple times about the same Person provided it was made by
different UserId's? If so, the FDs in 1 and 2 cannot be true but
FD: Person + Comment + UserId -> CommentId may be true.
4) Can the same Comment be made multiple times about the same Person by the same UserId but
have different Scores? This implies FD: Person + Comment + UserId' + Score -> CommentId is true and the others are false.
Exactly one of the above 4 FD's above must be true. Whichever it is affects how your data model is normalized.
Suppose FD: Person + Comment + UserId -> CommentId turns out to be true. The logical
consequences are that:
Person + Comment + UserId and CommentId serve as equivalent keys with respect to Score
Score should be put in a relation with one but not both of its keys (to avoid transitive dependencies).
The obvious choice would be CommentId since it was specifically created as a surrogate.
A relation comprised of: CommentId, Person, Comment, UserId is needed to tie the
Key to its surrogate.
From a theoretical point of view, the surrogate key CommentId is not
required to make your data model or database work. However, its presence may affect how relations are constructed.
Creation of surrogate keys is a practical issue of some importance.
Consider what might happen if you choose to not use a surrogate key but the full
attribute set Person + Comment + UserId in its place, especially if it was required
on multiple tables as a foreign or primary key:
Comment might add a lot of space overhead
to your database because it is repeated in multiple tables. It is probably more than a couple of characters long.
What happens if someone chooses to edit a Comment? That change needs to be propagated
to all tables where Comment is part of a key. Not a pretty sight!
Indexing long complex keys can take a lot of space and/or make for slow update performance
The value assigned to a surrogate key never changes, no matter what you do to the values
associated to the attributes that it determines. Updating the dependant attributes is now
limited to the one table defining the surrogate key. This is of huge practical significance.
Now back to whether you should be creating a surrogate for Person. Does Person live
on the left hand side of many, or any, FDs? If it does, its value will propogate through your
database and there is a case for creating a surrogate for it. Whether Person is a text or numeric attribute is irrelevant to the choice of creating a surrogate key.
Based on what you have said, there is at best a weak argument to create a
surrogate for Person. This argument is based on the suspicion that its value may at some point become a key or part of a key at some point in the future.
Here's the deal. Whenever you create something, you want to make sure that it has room to grow. You want to try to anticipate future projects and future advancements for your program. In this scenario, you're right in saying that there is no need currently to add a persons table that just holds 1 field (not counting the ID, assuming you have an int ID field and a person name). However, in the future, you may want to have other attributes for such people, like first name, last name, email address, date added, etc.
While over-normalizing is certainly harmful, I personally would create another, larger table to hold the person with additional fields so that I can easily add new features in the future.
Whenever you're dealing with users, there should be a dedicated table. Then you can just join the tables and refer to that user's ID.
user -> id | username | password | email
comment -> id | user_id | content
SQL to join the comments to the users:
SELECT user.username, comment.content FROM user JOIN comment WHERE user.id = comment.user_id;
It'll make it so much easier in the future when you want to find information about that specific user. The amount of extra effort is negligible.
Concerning the "score" for each comment, that should also be a separate table as well. That way you can connect a user to a "like" or "dislike."
With this database, you might feel that it is okay but there may be some problem in the future when you want the users to know more from the database.Suppose you want to know about the number of comments made on a person with the name='abc'.In this case ,you will have to go through the entire table of comments and keep counting.In place of this, you can have an attribute called 'count' for every person and increment it whenever a comment is made on that person.
As far as normalization is concerned,it is always better to have a normalized database because it reduces redundancy and makes the database intuitive to understand. If you are expecting that your database will go large in future then normalization must be present.