In this database, key1 & key2 make up the composite primary key of table4, but i'm able to add a foreign key to table3 that comprise just key1.
Why MySQL allows this? Does the above database design make no sense at all?
This answer takes the question's "add a foreign key to table3" to mean that a FK (foreign key) was added in table3 referencing one of the columns of the composite PK (primary key) of table4. In standard SQL a FK can reference a proper/smaller subset of a PK.
This other answer presumably takes "add a foreign key to table3" to mean that a FK was added in table4 with one of the columns of the PK referencing table3. A FK column set in a table is independent of any PK or UNIQUE declarations in it.
In standard SQL a FK can reference a proper/smaller subset of a PK.
The referenced column list must be declared PRIMARY KEY or UNIQUE. (PRIMARY KEY creates a UNIQUE NOT NULL constraint.) (The constraint has to be explicit, even though any set of NOT NULL columns containing a set that is UNIQUE has to be unique.)
Unfortunately MySQL lets you declare a FK referencing a column list that is not UNIQUE. Even though such a FK or one referencing non-NULL columns (OK in standard SQL) is not implemented properly, and the documentation itself advises not doing it:
The handling of foreign key references to non-unique keys or keys that contain NULL values is not well defined for operations such as UPDATE or DELETE CASCADE. You are advised to use foreign keys that reference only keys that are both UNIQUE (or PRIMARY) and NOT NULL.
(You can ponder just what are and are not the well-defined operations, since the documentation doesn't actually clarify.)
1.8.2.3 Foreign Key Differences
13.1.18 CREATE TABLE Syntax
13.1.18.6 Using FOREIGN KEY Constraints
PS Re relational vs SQL
In the relational model a FK references a CK (candidate key). A superkey is a unique column set. A CK is a superkey containing no smaller superkey. One CK can be called the PK (primary key). When a column set's values must appear elsewhere we say there is an IND (inclusion dependency). A FK is an IND to a CK. When an IND is to a superkey we could call that a "foreign superkey".
An SQL PK or UNIQUE NOT NULL declares a superkey. It is a CK when it does not contain a smaller column set declared as SQL PK or UNIQUE NOT NULL. SQL FK declares a foreign superkey. So an SQL PK might actually be a relational PK (hence CK) and a UNIQUE NOT NULL might actually be a CK. An SQL FK to one of these actually is a relational FK.
Foreign keys are not dependent of primary keys at all. In fact, they have nothing to do with primary keys.
A primary keys single purpose is to identify a row uniquely.
A foreign keys purpose is to make sure that for each entry in the referencing table (the child table) there must be an entry in the referenced table (the parent table). It's only a technical requirement in MySQL that there must be an index (not necessarily a primary key or a unique key, a simple index suffices) on the referenced column.
Therefore your design makes sense, yes.
Related
Suppose I have two tables in mysql
1.Child(name,father_name)
2.Father(name,contact)
The table Father has a composite key (name,contact).Father_name in Child table references name in father . Thus a foreign key references a part of primary key.This is allowed by mysql.
However consider the following situation:
Table father has the following tuples:
(kishan,9906011111)
(kishan,9990601234)
Now suppose I insert a row in child
(xyz,kishan)
How would I know which kishan in the father table is the child xyz related to ?
This situation could have been avoided if mysql does not allow a foreign key to refer a part of the primary key .
Please answer what's the benefit of this scheme allowed by mysql ?
This is a peculiarity of MySQL. In my opinion, foreign keys should only be to unique keys or primary keys. There should not be a mapping to "sets" of values using a foreign key relationship.
Clearly, the designers of MySQL disagree (both with me and other database implementors). They allow foreign key relationships to any columns that are indexed -- in MySQL parlance, are defined as a "key". If you have a composite primary key, then the initial column(s) are such a key.
To prevent problems and make your tables unambiguous and easy to use, I would recommend:
All tables have an auto-incremented primary key.
All foreign key relationships are only to primary keys (not to unique keys or other types of key).
The primary key be named the singular of the entity followed by id (example: things would have thingId as a primary key).
The foreign key have the same name as the primary key (except when this is not possible because there are multiple foreign key relationships to the same table).
Let's say table B is dependent on table A.
Table B has a unique primary key B.B_ID and a foreign key B.A_ID
which references the parent table A's primary key.
Since B has a unique key, is B.A_ID, the foreign key, a non key (non-key)
in B?
Thank you.
In the context of discussing the 2nd normal form, "non-key columns" are all the columns that are not part of a candidate key.
You may certainly have foreign key columns in a table that are not part of that table's primary key.
Suppose you have a table Person that has a primary key PersonName because that is the column you use to identify each person uniquely.
You can also have a column in that table such as CountryOfCitizenship that is a foreign key referencing another table Country. This foreign key column is not part of the primary key in the Person table; it is not the way we identify each row in that table.
Re your comment:
The second normal form requires that non-key columns have a functional dependency on the whole primary key. This is different from first normal form only if your primary key has multiple columns.
Functional dependency means that the attribute column unambiguously relates to the primary key, and therefore the value in the attribute column belongs on the same row with that primary key.
So if a column like CountryOfCitizenship always contains the country name that is the country of citizenship for the person who is named in that same row's primary key, then the attribute satisfies 1NF and since the table has a single-column primary key, it's automatically in 2NF as well.
In MySQL terminology, "key" usually refers to an explicit key which has an index on it. If you use this definition, then a primary key is a key. And a unique key is a key. And an index key is a key. But a foreign key is not necessarily a key.
When you declare a foreign key constraint, MySQL does not necessarily build an index on the referring table (it does in innodb). Of course, you can declare the foreign key to also be a key and guarantee that an index is built.
A FOREIGN KEY constraint does not have to be linked only to a PRIMARY KEY constraint in another table; it can also be defined to reference the columns of a UNIQUE constraint in another table.
You can find more information here https://stackoverflow.com/a/18435114/7667467
This may sound confusing and or simple but..
If I use a foreign key from Table B in Table A, which has a separate primary key. Do I need to include Table A's primary key as a foreign key in Table B?
Thanks!
========================================================================
EDIT:
Okay, let me try and clarify my question a bit.
In the case above, should I use Taco_ID as a FK in Table 2? Or is does it completely unnecessary?
In general, you don't usually make foreign keys bidirectionally like that. If you do, it means that the two tables exist in a 1-to-1 relationship: Each taco has a type, and each taco type can only be used by one taco. If you have a relationship like this, there's not really any reason to have them in separate tables, they could just be additional columns in the same table.
Normally foreign keys are used for 1-to-many or many-to-many relationships.
A 1-to-many relationship would be if many different tacos can be of the same type. They each have Taco_Type_ID foreign key.
For a many-to-many relationship, you typically use a separate relation table.
CREATE TABLE Taco_Types (
Taco_ID INT, -- FK to Table1.Taco_ID
Taco_Type_ID INT, -- FK to Table2.Taco_Type_ID
PRIMARY KEY (Taco_ID, Taco_Type_ID)
);
foreign keys and primary keys are SOMETIMES related, but not always. A foreign key in a table literally just means "whatever value is in this field MUST exist in this other table over ---> here". Whether that value is a PK or not in that other table is irrelevant - it just has to exist, and it has to be unique. That may fit the bill of being a primary key, but being primary is NOT required.
You can have composite foreign keys, e.g. in a (silly) address book, the child table you list a person's phone numbers in COULD be keyed with (firstname, lastname), but that runs into the problem of "ok, which John Smith does this number belong to?".
In most databases, foreign key references must be to primary keys or unique keys (and NULLs are allowed). MySQL recommends this but does not require it:
However, the system does not enforce a
requirement that the referenced columns be UNIQUE or be declared NOT
NULL. The handling of foreign key references to nonunique keys or keys
that contain NULL values is not well defined for operations such as
UPDATE or DELETE CASCADE. You are advised to use foreign keys that
reference only UNIQUE (including PRIMARY) and NOT NULL keys.
Do you need to reference primary keys for a foreign key relationship? First, you don't even need to declare foreign key relationships. I think they are important because they allow the database to maintain referential integrity. But, they are not required. Nor is there any semantic difference in queries, based on the presence of foreign keys (for instance, NATURAL JOIN does not use them). The optimize can make use of the declared relationship.
Second, if you are going to declare the foreign key, I would recommend using the primary key of the referenced table. That is, after all, one of the major reasons for having primary keys.
Foreign key should necessarily be a candidate key for a table (say table1)? I know that Foreign key references primary key of some other table (say table2). But for the table1, is it necessary that it should be candidate key?
By definition a foreign key is required to reference a candidate key in the target table (table2 in your question). A foreign key does not have to be a candidate key in the referencing table or be part of a candidate key in that table.
No. You can have a 1:N relationship, the FK requirement just says that the field has to exist in the other table. Whether that field is unique or not, does not matter.
For reference:
a candidate key is an alternative to a PK, it can be one field or the combination of fields (as in a concatenated key)
all this establishes is that there is more than one way to uniquely identify a record of the table
a good alternative to an employee_id might be ssn (social security number)
a concatenated key is multiple fields that make up the uniqueness of a record, which can either be an alternative to a PK, or together, act as the PK
because RDBMSs follow at least 1NF, all the fields of the table could be used as the concatentated key
Note: this is a bad choice and only serves as an example
think of an employee_id field as the one PK of the table, but the combination of firstname,lastname, and startdate would probably uniquely identify everyone on your employees table
Note: this is an example, there would probably be better alternatives to this in practice
Say I have the following table:
TABLE: widget
- widget_id (not null, unique, auto-increment)
- model_name (PK)
- model_year (PK)
model_name and model_year make up a composite key. Is there any problem to using widget_id as a FK in another table?
A key is any number of columns that can be used to uniquely identify each row within the table.
In the example you've shown, your widget table has two keys:
model_name, model_year
widget_id
In standard SQL, a foreign key may reference any declared key on the referenced table (either primary key or unique). I'd need to check MySQLs compliance.
From MySQL reference manual on foreign keys:
InnoDB permits a foreign key to reference any index column or group of columns. However, in the referenced table, there must be an index where the referenced columns are listed as the first columns in the same order.
As an alternative, if you wish to use the composite key from your referencing table, you'd have two columns in that table that correspond to model_name and model_year, and would then declare your foreign key constraint as:
ALTER TABLE OtherTable ADD CONSTRAINT
FK_OtherTable_Widgets (model_name,model_year)
references Widgets (model_name,model_Year).
Re InnoDB vs MyISAM, in the docs for ALTER TABLE
The FOREIGN KEY and REFERENCES clauses are supported by the InnoDB storage engine, which implements ADD [CONSTRAINT [symbol]] FOREIGN KEY (...) REFERENCES ... (...). See Section 13.6.4.4, “FOREIGN KEY Constraints”. For other storage engines, the clauses are parsed but ignored. The CHECK clause is parsed but ignored by all storage engines. See Section 12.1.17, “CREATE TABLE Syntax”. The reason for accepting but ignoring syntax clauses is for compatibility, to make it easier to port code from other SQL servers, and to run applications that create tables with references. See Section 1.8.5, “MySQL Differences from Standard SQL”.
I have no experience specific to my-sql, but with database-modeling in general
It is really important to understand the difference between primary and secondary keys.
Even if many db (I know for sure Oracle does) permit to specify an unique (simple or composite) key as the FK target, this is not considered a best practice. Use the PK instead.
FK to a secondary key should be used imo only to relate to tables that are not under your control.
In your specific case, I would certainly FK to widget_id: that is because the widget_id should be your PK, and the composite only made unique (and not null of course). This leads to better performance in mane cases, as you join only one column in queries, and is generally considered a best practice (google 'surrogate key' for more info)
MySQL will create an index on the column if there isn't one it can use:
InnoDB requires indexes on foreign
keys and referenced keys so that
foreign key checks can be fast and not
require a table scan. In the
referencing table, there must be an
index where the foreign key columns
are listed as the first columns in the
same order. Such an index is created
on the referencing table automatically
if it does not exist. (This is in
contrast to some older versions, in
which indexes had to be created
explicitly or the creation of foreign
key constraints would fail.)
index_name, if given, is used as
described previously.
http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
Let's say you have two tables. The first table looks like this:
TABLE: widget
- model_name (PK)
- model_year (PK)
- widget_id (not null, unique, auto-increment)
If you want to make another table that refers to unique records in the first table, it should look something like this:
TABLE B: sprocket
- part_number (PK)
- blah
- blah
- model_name_widget (FK to widget)
- model_year_widget (FK to widget)
- blah
With compound primary keys, you have to include all key fields in your FK references to make sure that you are uniquely specifying a record.