How to model diamond like many-to-many relationship in database ERD - mysql

Legend:
PK (Blue): Primary key
FK (Green): Foreign key
PFK (Blue): Primary Key and Foreign Key at the same time
How to model a diamond like (if term is correct) relationship? Better to explain using a simplified example:
There is organization, item and tag entities.
My aim is to model:
Every tag is unique by itself and belongs to a single organization.
Every item is unique by itself and belongs to a single organization.
Items have many tags (joined using M2M table) and related tag/item pairs must belong to same organization. (i.e. item from organization A cannot pair with a tag from organization B)
I diagrammed two alternative solutions, but none of them satisfied me.
Diagram 1 breaks 3rd aim: items and tags are unique by themselves using id as primary key, but there is nothing to stop insert pairs into item_tag which belong to different organization.
Diagram 2 does not break, but bends 1st and 2nd aims: organization_id is added as a Primary and Foreign Key to item and tag tables and item_tag.organization_id column references both. This prevents pairs from different organization. tag.id and item.id columns are part of a unnecessary composite primary key now, because in reality single id column represents uniqueness of the item and tag.
How can I model those requirements correctly?

To enforce referential integrity, you'll have to ...
include organization_id in all tables
create logically redundant UNIQUE (or PK) constraints on (organization_id, id) in both tables tag and item
have multicolumn FK constraints in item_tag matching the columns of those UNIQUE constraints.
If you don't include the organization_id (logically redundantly) there would be nothing to keep you from linking items and tags from different organizations (by mistake).
That would be your diagram 2. But do you really need data type uuid for tags? bigint or even int should suffice, while being a bit smaller and faster.
Closely related case with code example for PostgreSQL:
Enforcing constraints “two tables away”

Related

Can A Foreign Key Be Used More than Once?

Apologies for the newbie question.
The primary key of a table, such as Holiday, would be something like Holiday_ID. Holiday reference a get-away ticket that you can buy to go on a type of holiday, based on the ticket you buy.
Suppose I used Holiday_ID in a composite entity with Customer_ID to identify an instance of Holiday associated with customer, for whatever purpose.
However, suppose I also want to keep track of other information related to this instace: how much has the customer paid for the ticket, how much has the customer yet to pay for the ticket
I have two options:
a) I can create another composite entity. However, I am not sure if I can do that because I am not sure if you can use a particualr foreign key more than once
b) I can create a composite/associate entity, however, I am not sure if you can create a composite entity with more than two foreign keys?
To answer the technical parts of your question, once you create a composite unique or primary key, ONLY ONE record in the table can have the same values in the set of fields defined in that key. SO, no, you cannot reuse the holidayId key WITH THE SAME customer. You can use it with another, different customer if you wish.
Second, there is no limit to the number of attributes that can be included in a Unique or primary key. If you need, and if it's appropriate and conforms to the rules of normalization, the key can include all the attributes of the table.
Third, to answer your question below, Any column, or set of columns in a table can be defined as a Foreign Key, as long as it is also the primary key or unique key of some table in the database. And there can be any number of FKs defined in a table, they can even overlap. (you can have HolidayId as a FK, and also have HolidayID and CustomerId as a composite FK) the only restriction is that the FK must reference a Primary or Unique Key of some table in the database.(It can also be the same table the FK is in as well, as when you add a supervisorId to an employee Table that is a FK to the EMployeeId of the same employee table)
This example illustrates one of the problems of using surrogate keys without also using a natural key. to wit, what, exactly is a "Holiday"? Is Christmas 2016 the same "Holiday" as Christmas 2015? Is Christmas in Aruba the same holiday as Christmas in Hawaii?
and then, about the composite table to identify associations of customer with Holiday, is it the same association if the customer goes to Aruba on Christmas the next year, or a different instance? What does the row in the table represent if the customer wants 5 tickets?
The first thing that should be done in database design is a logical design which defines, as clearly and unambiguously as possible, in business terms, the meanings of the entities for each table in the database.

Products and Bill of Materials

I have a products table link to a bill of materials table. See diagram
Each product can have more than one formula. For example:
Currently ProdIDNeed and ProdIDNeeded are my composite primary key, both fields also link as foreign keys to ProdID (Products). The only way I can think of preventing a key violation is to create a Formula field and have a 3 field composite primary key (ProdIDNeed, ProdIDNeeded, FormulaNumber).
However, I have to link the product_billmaterials table to a workorders table (bascially an order to make the product according to formula). Linking three fields to another table is a pain.
I guess I could also create a surrogate key on the product_billmaterials table which I am not too crazy about either.
Is there any other way I can organize this or must I choose one of the options I have thought of?

Database Relationships - One-to-One that also has One-to-Many

Let's say you have one cook that has one restaurant, and vice versa. So with a one-to-one relationship, you would have the primary key id in the cooks table and cook_id as the primary and foreign key in the restaurants table.
So how would you represent a relationship of one-to-many between the restaurant and its customers? Since the restaurant does not have its own ID, would the customers table have its own id and then contain foreign keys of cook_id?
Edit: I've thought of a better and more realistic example. Let's say you have a work order that only ever has one quote. You'll have the work order's id in the quotes table, since it's 1-to-1. Being a quote, it's bound to change, and that same particular quote gets revised. If you wanted to record the revisions made to a quote (or some sort of history log), you'd want something like a quote_revisions table. In this case, a work order only ever has one quote, and a quote can have many quote revisions. With what IDs do you link the quotes and quotes_revisions table?
Since you have a one-to-one relationship, the cook's id is the restaurant's id too. You can relate customers to restaurants by associating customer keys with cook/restaurant keys in a table (customers or another table). The one-to-many cardinality is enforced by placing a unique constraint on the customer's key so that they can't be associated with more than one restaurant/cook.
Using the Work_order example:
Work_order would have a PK of, say, wo_id, and it might be AUTO_INCREMENT.
Quotes would have a PK with the same wo_id, but not AUTO_INCREMENT.
Quote_revisions would have an INDEX(wo_id), but some other column(s) for the PK.
Work_order and Quotes are "1:1", as provided by wo_id.
Quotes and Quote_revisions are "1:N"; wo_id in both tables provides that relationship.
It is rarely useful to have 1:1, but your example might be a good use case. (One table is relatively large and static, the other is relatively small and frequently changed.)
I would instead have a restaurant_id field as the primary key in the restaurant table, along with cook_id as a foreign key. Yes, this structure would support a one-to-many relationship just as well as a one-to-one relationship, but I believe each entity should nevertheless have its own ID. If you like, you can put a unique constraint on the foreign key, to ensure that the relationship does remain one-to-one. Or you could simply have a single restaurant table that includes fields with information about its head chef.

In what case adding an ID field to a many-to-many table might be a good idea?

Let's say there are two entities - Product and Image with a many-to-many relationship between them. The order of images associated with each product does matter.
Product
------------------------------------
ProductID (primary key)
ProductName
...
Image
------------------------------------
ImageID (primary key)
Url
Size
...
What are the cons and pros of the following three many-to-many "bridge" table approaches for solving this problem?
ProductImage
------------------------------------
ProductImageID (primary key, identity)
ProductID (foreign key)
FullImageID (foreign key)
ThumbImageID (foreign key)
OrderNumber
or
ProductImage
------------------------------------
ProductID (primary key, foreign key)
IndexNumber (primary key)
FullImageID (foreign key)
ThumbImageID (foreign key)
or
ProductImage
------------------------------------
ProductID (primary key, foreign key)
FullImageID (primary key, foreign key)
ThumbImageID (foreign key)
OrderNumber (index)
There is no purpose (that I have ever found) in adding a surrogate key (i.e. the IDENTITY field) to a many-to-many "bridge" table (or whatever you want to call it). However, neither of your proposed schemas is correct.
In order to get the ideal setup, you first need to determine the scope / context of the following requirement:
The order of images associated with each product does matter.
Should the ordering of the images be the same, in relation to each other, regardless of what Products they are associated with? Meaning, images A, B, C, and D are always in alphabetical order, regardless of what combination of them any particular Product has.
Or, can the ordering change based on the Product that the Image is associated with?
If the ordering of the Images needs to remain consistent across Products, then the OrderNumber field needs to go into the Image table. Else, if the ordering can change per Product, then the OrderNumber field go into this bridge / relationship table.
In either case:
the PK is the combination of FKs:
A Primary Key uniquely, and hopefully reliably (meaning that is doesn't change), identifies each row. And if at all possible, it should be meaningful. Using the combination of the two FK fields gives exactly that while enforcing that uniqueness (so that one Product cannot be given the same Image multiple times, and vice-versa). Even if these two fields weren't chosen as the PK, they would still need to be grouped into a UNIQUE INDEX or UNIQUE CONSTRAINT to enforce that data integrity (effectively making it an "alternate key"). But since these IDs won't be changing (only inserted and deleted) they are well suited to be the PK. And if you are using SQL Server (and maybe others) and decide to use this PK as the Clustered index, then you will have the benefit of having both ProductID and ImageID in any Non-Clustered Indexes. So when you need to sort by [OrderNumber], the Non-Clustered Index on that field will automatically be a covering index because the only two data fields you need from it are already there.
On the other hand, placing the [OrderNumber] field into the PK has a few downsides:
It can change, which is not ideal for PKs.
It removes the ability to enforce that a ProductID and ImageID can only relate to each other one time. Hence would need that additional UNIQUE INDEX or UNIQUE CONSTRAINT in order to maintain the data integrity. Else, even if you include all 3 fields in the PK, it still allows for the ProductID + ImageID combination to be there multiple times per various values of IndexID.
there is no need for an IDENTITY field:
With the above information in mind, all of the requirements of a PK have already been met. Adding a surrogate key / auto-increment field adds no value, but does take up additional space.
And to address the typical reply to the above statement regarding the surrogate key not adding any value, some will say that it makes JOINs easier if this combination of ProductID+ImageID needs to be Foreign Keyed to a child table. Maybe each combination can have attributes that are not singular like [OrderNum] is. An example might be "tags" (although those would most likely be associated with just ImageID, but it works as a basic example). Some people prefer to only place a single ID field in the child table because it is "easier". Well, it's not easier. By placing both ImageID and ProductID fields in the child table and doing the FK on both back to this PK, you now have meaningful values in the child table and will not need to JOIN to this [ProductImage] table all of the time just to get that information (which will probably be needed in most queries that are not simply listing or updating those attributes for a particular ProductID+ImageID combination). And if it is not clear, adding a surrogate key still requires a UNIQUE INDEX or UNIQUE CONSTRAINT to enforce the data integrity of unique ProductID+ImageID combinations (as stated above in the first bullet point).
And placing both ID fields into the child table is another reason to stay away from fields that can change when choosing a PK: if you have FKs defined, you need to set the FK to ON UPDATE CASCADE so that the new value for the PK propagates to all child tables, else the UPDATE will fail.
ProductImage
------------------------------------
ProductID (primary key, foreign key to Product table)
FullImageID (primary key, foreign key to Image table)
ThumbImageID (foreign key; shouldn't this field be in the Image table?)
OrderNumber TINYINT (only here if ordering is per Product, else is in Image table)
The only reason I can see for adding a surrogate key in this situation is if there is a requirement from some other software. Things such as SQL Server Replication (or was it Service Broker?) and/or Entity Framework and/or Full-Text Search. Not sure if those examples do require it, but I have definitely seen 1 or 2 "features" that require a single-field PK.
The best way to achieve this is by having three tables, one for products, one for images and one for their relationship
products
--------
+ product_id (pk)
- product_name
- product_description
- ...
images
------
+ image_id (pk)
- image_title
- ...
product_images
--------------
+ product_id (fk)
+ image_id (fk)
Why do you have seperate tables for fullImage and thumbImage?
Table1 is better since it allows you identify individual rows inside the table.
Table2, im sure you can't have two primary keys.
It might be better to have an Image table as follows.
ImageId (primary)
FullImage [actual value/FK]
ThumbNail [actual value/FK]
and then,
ProductImageID (primary)
ProductID [FK]
ImageID [FK]
How that helps,
Regards,
Rainy

Mysql composite primary key

I want to have a lookup table that links two of the same things to eachother. Say I have a 'Person' table and I want to lookup the relationship between two people. I'll have column one of the lookup be 'PersonId1' and column two be 'PersonId2' and the third column be 'Relationship'. Since the relationship goes both ways I don't need to have duplicate records with the PlayerId's switched. Is there any way to make mysql enforce uniqueness on PlayerId1 and PlayerId2 combinations regardless of which order they're in?
Does that make sense?
Short answer: No.
Longer answer: You could set up a trigger to swap the order of the two person ids if the second were smaller than the first, then write them, and use a composite key.
Even longer answer: Not all interpersonal relationships are commutative (not all relationships go both ways). What about the "Employee" or "Mother" relationships? Even the "Friend" relationship, which is presumably peer-to-peer, might be better represented if you had separate rows saying A is B's Friend and B is A's Friend. So maybe you want a three-field composite key on this table.
You mean you want to have a unique row record from PersonID1 and PersonID2 Column (regardless of the Relationship column)? If that so, you may use the Composite key (Multi column key).
Here's an example:
CREATE TABLE Person (
PersonId1 INT,
PersonId2 INT,
PRIMARY KEY (PersonId1, PersonId2)
)
+1 for composite pk. To prevent duplicate combinations, an extra varchar column with for example personid1+personid2 with a unique constraint on it may be a solution...
See also: person data model example