Related
I am modeling a database for a webshop and have come across ad issue. Basically the question is whether to ignore database normalization rules for simplicity's sake.
Below is the relevant part of my diagram prior to the issue.
Database diagram
Basically, the product can have options (size, flavor, color) but only from one option group. Since an option group can have many options and a product that uses it can take a subset, a ProductOption table is created. Next we have a SpecialOffers table. Next, a special offer can have many products and products can belong to many special offers, hence the association table SpecialOfferProducts. All this works fine until the special offer includes a product that has options. This is where I run into problems. I have a couple of ideas.
First idea:
Create an association table between SpecialOfferProducts and ProductOptions. I don't like this idea since both tables have composite primary keys and creating a table that has a composite primary key composed of two composite primary keys seems really weird and I have never seen anything like it.
Second idea:
Create a association table between SpecialOfferProducts and Options. This seems wrong since Options is not directly tied to Product. Still this would work and the primary key would be a little simpler.
Third idea:
This is the one that I like the most but it violates a few rules. Change the SpecialOfferProducts table. Make it have its own primary key and have SpecialOffers, Products and Options as foreign keys. Simply make the Options foreign key nullable and problem solved. Of course the problems are that I am not making an association table where I should and am making a foreign key nullable. This would slightly complicate my code to deal with all of this but I still feel that this is much simpler than the other approaches since I reduce the number of composite keys and I don't have to add another table in the case where the product in a special offer uses an option.
My question is, which one of this options is best? Is there a better option I have not mentioned?
Using Martin style notation
OptionGroups has (0,n) relationship with the table Options. Options has (1,1) relationship with the table OptionGroups. The purpose of these table is to store information like color, size, etc. An example wouldbe OptionGroups entry color that has Option entries black, white, etc.
Product table has (0,1) relationship with table OptionGroups. OptionGroups has (0,n) relationship with table Product. Product table has a (o,n) relationship with the table Options. Options table has a (o,n) relationship with the table Product. Many-to-many relation produces association table ProductOptions. ProductOptions has a composite PK ProductID, OptionsID. The purpose of these tables is to allow product to have (but does not have to have) options from a certain option group but does not need to have all options from that group.
Example 1. Product does not have any options, hence FK Product_OptionGroups is null. In this case the product does not have any entries in the ProductOptions table.
Example 2. Product has options (lets say color) and so the FK Product_OptionGroups is not null (has the ID of the coresponding option group). Option group color can have many colors and the product is allowed to use one or many of those colors. The colors in use by the product are entries in the table ProductOptions.
SpecialOffer table has a (1,n) relation to the table Products. Products table has a (0,n) relation to the table SpecialOffer. Many-to-many relation creates the association table SpecialOfferProducts. This table has a PK SpecialOfferID, ProductID. The table has a Quantity attribute indicating the quantity of the product.
Example. SpecialOffer A includes one instance of Product A and two instances Product B.
Lets say that the Product A has options. Now SpecialOfferProducts table must reference the correct option.(maybe the product can be blue and red and the special offer only includes the red product). This is where the current schema does not work and either an additional table must be introduced (idea 1 and 2) or the existing tables changed (idea 3).
Maybe you have some relation(ship)/association not representable in terms of your first three:
-- special offer S offers the pairing of P and option O
SpecialOfferProductOption(S, P, O)
-- PK (S, P, O)
-- FK (S, P) to SpecialOfferProducts, FK (P, O) to ProductOptions
You don't seem to understand the use of composite keys, CKs (candidate key), FKs (foreign keys) & constraints. Constraints (PKs, UNIQUE, FKs, etc) arise after you design relation(ship)s/associations sufficient to clearly describe your business situations (represented by tables), per the situations that can arise.
From an ER point of view, you are not properly applying the notions of participating entity (type), entity (type) key & associative entity (type).
You are needlessly & vaguely afraid of composite CKs. Even if you wanted to reduce use of composite keys, you should first find a straightforward design. If you don't want to use composite keys, introduce id PKs along with other CKs. But note that when you use ids as FKs that doesn't drop the obligation to properly constrain the tables that they appear in to agree where necessary with other ids or columns per the constraints you would have needed if you had used the composite CKs instead.
First idea:
Create an association table between SpecialOfferProducts and ProductOptions. I don't like this idea since both tables have composite primary keys and creating a table that has a composite primary key composed of two composite primary keys seems really weird and I have never seen anything like it.
It's not clear what you mean by this. Maybe you mean the above (good) design. Maybe you mean having duplicate product columns; but that's not what good design suggests.
From an ER perspective: You may be thinking of this as a relation(ship)/association on special orders & products. But then the entity keys would not be composite, they would identify special orders & products, and also options would participate. Or we can use the ER concept of reifying relation(ship)s/associations SpecialOfferProducts & ProductOffers to associative entities that are the two participants. That would use composite keys. (If options weren't considered entities then ER would call this a weak relation(ship)/association entity with special orders & products as identifying entities.) Regardless, special orders & products must agree on options, and if that isn't enforced via FKs then it still needs constraining.
If you have (been) read(ing) some published text(s) on information modeling & database design (as you should) you will see many uses of composite keys.
Second idea:
Create an association table between SpecialOfferProducts and Options. This seems wrong since Options is not directly tied to Product. Still this would work and the primary key would be a little simpler.
It's not clear what you mean by "directly tied", "seems" or "wrong".
Relational tables relation(ship)s/associations are among values, certain subrows of which may identify certain entities. Just use the relevant columns & declare the relevant constraints.
From an ER perspective: Considering that you seem to be confused about participant entities (special offer vs SpecialOfferProduct), maybe this is moot, but: Maybe if you tried to express yourself only using technical terms & without the confusion then you would be trying to say that this design needs a constraint that product-option pairs appear in ProductOptions and that it's messy that the constraint involves a relation(ship)/association whose associative entity ProductOption isn't one of the participating entities. I'd agree, but such a design is not "wrong".
Third idea:
This is the one that I like the most but it violates a few rules. Change the SpecialOfferProducts table. Make it have its own primary key and have SpecialOffers, Products and Options as foreign keys. Simply make the Options foreign key nullable and problem solved.
Besides just being needlessly complex, this design is bad. It involves a complex table meaning & complex constraints. When settting the table value you need to decide when to use & not use nulls. When reading you need to figure out what a row means based on whether it has a null. Introducing an id or nulls, possibly while dropping columns, does not remove the obligation to constrain remaining columns if that's not handled by remaining FK constraints. Normally we combine tables while introducing nulls in columns that are not part of every CK--not your case. Here your adding ids doesn't even obviate the need to constrain pairs of products and non-null option column values to be in ProductOptions. And when there is a NULL option column value there should still exist certain rows in ProductOptions and sometimes not certain rows in SpecialOfferProducts. Also this design must be used with complex queries dealing with the presence of NULL. (Which you address.) Justifying this as an ER design is similarly problematic.
PS 1 Please explain your business relation(ship)s/associations with less generic terms than the essentially meaningless "has", "with", "uses", "in" & "belong to"--as you would with a client buying your products & special offers. They refer to relation(ship)s/associations & sets, but they don't explain them. (Similarly, cardinalities are properties of relation(ship)s/associations, but don't explain/characterize them.)
PS 2 ER reasoning about designs involves what (possibly associative) entities are participating in relationships, whereas in the relational model view tables just capture n-ary relation(ship)s/associations for any n. So the ER view is adding needless distinctions. That is why ER-based information modeling & database design approaches are not as effective as fact-based approaches:
This leads to inadequate normalization and constraints, hence redundancy and loss of integrity. Or when those steps are adequately done it leads to the E-R diagram not actually describing the application, which is actually described by the relational database predicates, tables and constraints. Then the E-R diagram is both vague, redundant and wrong.
PS 3 We don't need SpecialOfferProducts if it holds rows where "special offer S offers the pairing of P and some option", because it is select S, P from SpecialOfferProductOption. (This seems to be the case since your option 3 involves having only one table that you call SpecialOfferProducts but is like this table with an added id.) But if it holds rows where say "special offer S offers product P" and that can be so when not all of S's product-option pairs have been recorded then you need it. (Something similar arises re deciding when something is an entity, eg when there should be a table "S is a special option".)
PS 4
seems really weird and I have never seen anything like it
This is the story of life. But in a technical context if we learn and apply clearly defined basic definitions, rules & procedures then we "see" more, and more clearly. (And don't vaguely think we vaguely see things that aren't there.) And "weird" is a rare case where we can explicitly justify that our tools don't apply.
I have a small question concerning with how I should design my database. I have a table dogs for an animal shelter and I have a table owners. In the table dogs all dogs that are and once were in the shelter are being put. Now I want to make a relation between the table dogs and the table owners.
The problem is, in this example not all dogs have an owner, and since an owner can have more than one dog, a possible foreign key should be put in the table dogs (a dog can't have more than one owner, at least not in the administration of the shelter). But if I do that, some dogs (the ones in the shelter) will have null as a foreign key. Reading some other topics taught me that that is allowed. (Or I might have read some wrong topics)
However, another possibility is putting a table in between the two tables - 'dogswithowners' for example - and put the primary key of both tables in there if a dog has an owner.
Now my question is (as you might have guessed) what the best method is of these two and why?
The only solution that is in keeping with the principles of the Relational Model is the extra table.
Moreover, it's hard to imagine how you are going to find any hardware that is so slow that the difference in performance when you start querying, is going to be noticeable. After all, it's not a mission-critical tens-of-thousands-of-transactions-per-second appliation, is it ?
I agree with Philip and Erwin that the soundest and most flexible design is to create a new table.
One further issue with the null-based approach is that different software products disagree over how SQL's nullable foreign keys work. Even many IT professionals don't understand them properly so the general user is even less likely to understand it.
The nullable foreign key is a typical solution.
The most straightforward one is just to have another table of owners and dogs, with foreign keys to the owner and dog tables with the dog column UNIQUE NOT NULL. Then if you only want owners or owned dogs you do not have to involve IS NOT NULL in your queries and the DBMS does not need to access them among all owners and dogs. NULLs can simplify certain situations like this one but they also complicate compared to having a separate table and just joining when you want that data.
However, if it could become possible for a dog to have multiple owners then you might need the extra table anyway as many:many relationship without the UNIQUE NOT NULL column and the column pair owner-dog UNIQUE NOT NULL instead. You can always start with the one UNIQUE NOT NULL and move to the other if things change.
In the olden days of newsgroups, we had this guy called -CELKO- who would pop up and say, "There is a design rule of thumb that says a relational table should model either an entity or a relationship between entities but never both." Not terribly formal but it is a good rule of thumb in my opinion.
Is 'owner' (person) really an attribute of a dog? It seems to me more like you want to model the relationship 'ownership' between a person and a dog.
Another useful rule of thumb is to avoid SQL nulls! Three-valued logic is confusing to most users and programmers, null behavior is inconsistent throughout the SQL Standard and (as sqlvogel points out) SQL DBMS vendors implementation things in different ways. The best way of modelling missing data is by the omission of tuple in a relvar (a.k.a. don't insert anything into your table!). For example, Fido is included in Dog but omitted from DogOwnership then according to the Closed World Assumption Fido sadly has no owner.
All this points to having two tables and no nullable columns.
I wouldn't do any extra table. If for some reason no nulls allowed (it's a good question why) - I would, and I know some solutions do the same, put instead of null some value, that can't be a real key. e.g NOT_SET or so.
hope it helps
A nullable column used for foreign key relationship is perfectly valid and used for scenarios exactly like yours.
Adding another table to connect the owners table with the dogs table will create a many to many relationship, unless a unique constraint is created on one of it's columns (dogs in your case).
Since you describe a one to many relationship, I would go with the first option, meaning having a nullable foreign key, since I find it more readable.
I have a column with a uniqueidentifier that can potentially reference one of four different tables. I have seen this done in two ways, but both seem like bad practice.
First, I've seen a single ObjectID column without explicitly declaring it as a foreign key to a specific table. Then you can just shove any uniqueidentifier you want in it. This means you could potentially insert IDs from tables that are not part of the 4 tables I wanted.
Second, because the data can come from four different tables, I've also seen people make 4 different foreign keys. And in doing so, the system relies on ONE AND ONLY ONE column having a non-NULL value.
What's a better approach to doing this? For example, records in my table could potentially reference Hospitals(ID), Clinics(ID), Schools(ID), or Universities(ID)... but ONLY those tables.
Thanks!
You might want to consider a Type/SubType data model. This is very much like class/subclasses in object oriented programming, but much more awkward to implement, and no RDBMS (that I am aware of) natively supports them. The general idea is:
You define a Type (Building), create a table for it, give it a primary key
You define two or more sub-types (here, Hospital, Clinic, School, University), create tables for each of them, make primary keys… but the primary keys are also foreign keys that reference the Building table
Your table with one “ObjectType” column can now be built with a foreign key onto the Building table. You’d have to join a few tables to determine what kind of building it is, but you’d have to do that anyway. That, or store redundant data.
You have noticed the problem with this model, right? What’s to keep a Building from having entries in in two or more of the subtype tables? Glad you asked:
Add a column, perhaps “BuildingType”, to Building, say char(1) with allowed values of {H, C, S, U} indicating (duh) type of building.
Build a unique constraint on BuildingID + BuildingType
Have the BulidingType column in the subtables. Put a check constraint on it so that it can only ever be set to the value (H for the Hospitals table, etc.) In theory, this could be a computed column; in practice, this won't work because of the following step:
Build the foreign key to relate the tables using both columns
Voila: Given a BUILDING row set with type H, an entry in the SCHOOL table (with type S) cannot be set to reference that Building
You will recall that I did say it was hard to implement.
In fact, the big question is: Is this worth doing? If it makes sense to implement the four (or more, as time passes) building types as type/subtype (further normalization advantages: one place for address and other attributes common to every building, with building-specific attributes stored in the subtables), it may well be worth the extra effort to build and maintain. If not, then you’re back to square one: a logical model that is hard to implement in the average modern-day RDBMS.
Let's start at the conceptual level. If we think of Hospitals, Clinics, Schools, and Universities as classes of subject matter entities, is there a superclass that generalizes all of them? There probably is. I'm not going to try to tell you what it is, because I don't understand your subject matter as well as you do. But I'm going to proceed as if we can call all of them "Institutions", and treat each of the four as subclasses of Institutions.
As other responders have noted, class/subclass extension and inheritance are not built into most relational database systems. But there is plenty of assistance, if you know the right buzzwords. What follows is intended to teach you the buzzwords, in database lingo. Here is a summary of the buzzwords coming: "ER Generalization", "ER Specialization", "Single Table Inheritance", "Class Table Inheritance", "Shared Primary Key".
Staying at the conceptual level, ER modeling is a good way of understanding the data at a conceptual level. In ER modeling, there is a concept, "ER Generalization", and a counterpart concept "ER Specialization" that parallel the thought process I just presented above as "superclass/subclass". ER Specialization tells you how to diagram subclasses, but it doesn't tell you how to implement them.
Next we move down from the conceptual level to the logical level. We express the data in terms of relations or, if you will, SQL tables. There are a couple of techniques for implementing subclasses. One is called "Single Table Inheritance". The other is called "Class Table Inheritance". In connection with Class table inheritance, there is another technique that goes by the name "Shared primary Key".
Going forward in your case with class table inheritance, we first design a table called "Institutions", with an Id field, a name field, and all of the fields that pertain to institutions, no matter which of the four kinds they are. Things like mailing address fields, for instance. Again, you understand your data better than I do, and you can find fields that are in all four of your existing tables. We populate the id field in the usual way.
Next we design four tables called "Hospitals", "Clinics", "Schools", and "Universities". These will contain an id field, plus all of the data fields that pertain only to that kind of institution. For instance, a hospital might have a "bed capacity". Again, you understand your data better than I do, and you can figure these out from the fields in your existing tables that didn't make it into the Institutions table.
This is where "shared primary key" comes in. When a new entry is made into "Institutions", we have to make a new parallel entry into one of four specialized subclass tables. But we don't use some sort of autonumber feature to populate the id field. Instead, we put a copy of the id field from the "Institutions" table into the id field of the subclass table.
This is a little work, but the benefits are well worth the effort. Shared primary key enforces the one-to-one nature of the relationship between subclass entries and superclass entries. It makes joining superclass data and subclass data simple, easy, and fast. It eliminates the need for a special field to tell you which subclass a given institution belongs in.
And, in your case, it provides a handy answer to your original question. The foreign key you were originally asking about is now always a foreign key to the Institutions table. And, because of the magic of shared-primary-key, the foreign key also references the entry in the appropriate subclass table, with no extra work.
You can create four views that combine institution data with each of the four subclass tables, for convenience.
Look up "ER Specialization", "Class Table Inheritance", "Shared Primary Key", and maybe "Single Table Inheritance" on the web, and here in SO. There are tags for most of these concepts or techniques here in SO.
You could put a trigger on the table and enforce the referential integrity there. I don't think there's a really good out-of-the-box feature to implement this requirement.
Can a database table contains more than one primary key?
Yes, I am talking about RDBMS.
A table can have:
No primary keys;
One primary key consisting of one column; or
One composite primary key consisting of two or more columns.
Other than that you can have any number of unique indexes, which will do basically the same thing.
The primary key of a relational table uniquely identifies each record in the table.
So, in order to keep the uniqueness of each record, you cant have more than one primary key for the table.
It can either be a normal attribute that is guaranteed to be unique (such as Social Security Number in a table with no more than one record per person) or it can be generated by the DBMS (such as a globally unique identifier, or GUID, in Microsoft SQL Server). Primary keys may consist of a single attribute or multiple attributes in combination.
That's why it is called Primary Key because it is, well, PRIMARY
Yes, you can have Composite primary keys, that is, having two fields as a primary key.
"First of all, you have to understand the history of entity-relationship design methodology as well as understand the word "relational" in relational database management systems (RDBMS)."
May I suggest politely that you first get YOURSELF educated on these very same subjects before leading other people into flawed beliefs ? I'll respond to the two worst ones of your stupidities below.
"According to relational methodology principles, each entity should only have one and only one means to identify it."
That is about the biggest crap I have ever heard anybody spawn around about relational data design. The relational model does not constrain any "entity", as you erroneously call it, to have any precise number of keys. Any "entity" can have any number of keys, and EACH key is, by definition of its very property of making the "rows" unique, a valid candidate for any purpose of "identification". Choosing the most useful/appropriate one for use in certain contexts (foreign keys in referencing tables, e.g.), is a design issue, and the relational model does not have anything to say on such things.
"Therefore, "R"DBMS attempts to facilitate the modeling of entity relationships."
Codd's paper "A Relational model of date for large shared data banks", which marks the birth of the relational model, predates the invention of E-R by a number of years. So to say that the Relational model attempts to facilitate the modeling of E-R concepts, is having things COMPLETELY backwards, and nothing but a display of one's own complete and utter ignorance of "the history" that you referred to in your own answer.
The short answer is yes. A primary key is a candidate key and is in principle no different to any other candidate key. It is a widely observed convention that one candidate key per table is designated as the "primary" one - meaning that it is "preferred" or has some special meaning for the database designer or user. This is just convention however. It is only a label of convenience and a reminder about the potential significance of one key. In practice all keys can serve the same purpose and the "primary" one is not special or unique in any fundamental way.
First of all, you have to understand the history of entity-relationship design methodology as well as understand the word "relational" in relational database management systems (RDBMS).
In order to define the bounds of an entity and relationships to be formed, there must be a unique handle or a unique combination of handles to identify each single instance of an entity and then to form relationships between them.
You also need to understand the meaning/root of the word "identify" which is to zero in on the "identity" of each instance of an entity. "identity" being the mathematical term meaning "one" or a singularity.
According to relational methodology principles, each entity should only have one and only one means to identify it. Therefore, "R"DBMS attempts to facilitate the modeling of entity relationships. Note the differences between "Entity/Class" and "Entity/Class instance".
However, RDBMS is used widely and mostly by people not so interested in accurately portraying the E-R design principles. So that frequently, we have more than one possible entity-definition sitting inside a table, which I call entity-aliasing. Opposed to identity-aliasing, where two or more instances of an entity-set hides under the same key, entity-aliasing is like the table
EmpProj([empId], empName, empAddr, projId, projLoc)
actually has two entity-sets aliased under the same table:
Emp([empId], empName, empAddr)
Proj([projId], projLoc, empId)
That is when normalisation comes in - to separate these entities out. Try as we might to do a decent design normalisation, computer scientists may not have as good a perspective on the information as a statistician. The computer scientist (which in this discussion includes everyone with a decent knowledge of ER design) tries his/her best in creating a schema that cleanly defines entities and their relationships.
However, after 18 months analysing voluminous information from the database, the statistician begin to see principal components that emerge whose analyses is terribly crippled due to the misalignment of the principal components with those of boundaries of the computer scientists' perceived entities.
That is where alternate unique keys are good for - to identify instances of entities due to the principal components existing as ghost-entities in the database.
Therefore, the primary key of a table is because that table is perceived to be a perfect entity as an entity should have only one primary key, be it singular or composite.
As far as the statistician is concerned, even though the database allows only one primary key per table, the alternative unique keys is to the statistician the primary keys to those ghost-entities. Which is why sometimes you are frustrated by statisticians who seem to do double work by downloading the data into the local database of their workstation/PC.
In conclusion, the constraint placed by the "R"DBMS manufacturer in allowing only one primary key per table is their pretense in believing that they know how information behave and believing that principal components of the information due to the population do not mutate over time.
If you have more than one unique keys possible in a table it means either one or more of the possibilities
Like myself, you are lazy to
separate them since they seem to
work quite well
For performance' sake, mixing the
entities into the same table makes
the application run incredibly
faster
Like the statistician, you gradually
discover ghost entities in your
information.
I'm in the process of creating a social network. It has several entities like news, photo, which can have comments. Since all comments have the same columns and behave the same way, and the only difference is their type — news, or photo, or something else to be added in the future — I decided to create one table for all comments with a column named type. It worked perfectly until I decided to add foreign keys to my database schema.
The comment table have a column parent, which refers to id of news or photo table, depending on the column type.
The problem is, I can't add a foreign key which refers to the unknown in advance table, and even more, which refers to several tables at once.
The whole database now uses foreign keys, except this one parent column in the comment table. It bothers me because it's the only place where I can't add a foreign key.
I'm sure I can't create such a foreign key; something in my database design needs to be changed. I decided to create one table for comments to be ready to add new comment types for new entities in the future — video, music, article, etc — and don't run into maintenance hell when I want to add one new column for all comments.
If I absolutely have to create a separate table for each comment type to be able to use foreign keys fully, I'll do that. But maybe another common solution to this problem already exists, and I'm just not aware of it?
Maybe I should create some sort of link table, which links the comment table with other entities' tables? But maybe this solution is even more complex than creating a separate table for each comment type?
Maybe I should have several columns in the comment table, like newsId, photoId, to which I can add foreign key?
These solutions just don't seem elegant to me, or I just misunderstand something. My whole perception of this issue might be plain wrong. That's why I'm here. Please share your ideas.
I think your problem is that you have several entities - news, photos. But these are all just types of (say) items. Like comments,items will probably have some attributes in common as well as some distinct attributes. One of those attributes will be the ability to be commented upon.
In this approach you have a table CommentableItems (1), with the common attributes. Then you have some sub-tables NewsItems, PhotoItems, etc. It is quite easy to set-up the keys for these tables to enforce the required one-to-one relationship. Obviously, Comments has a foreign key which references CommentableItems.
(1) Actually I would probably shoot myself rather than allow a table called something as ghastly as CommentableItems into my schema, but this is just for the sake of example.