I'm trying to understand the difference between creating a FOREIGN KEY this way:
CREATE TABLE child(
id_child INT NOT NULL,
id_parent INT
FOREIGN KEY(id_parent) REFERENCES parent(id_parent));
rather than this one:
CREATE TABLE child(
id_child INT NOT NULL,
id_parent INT
CONSTRAINT FK_id_parent FOREIGN KEY(id_parent) REFERENCES parent(id_parent));
If I use the first form it will create a CONSTRAINT anyway (Innodb indexes, or am I wrong? not so illustrated about indexes). So, what's the need to explicitly declare the CONSTRAINT or there's no reason to do it?
Using the CONSTRAINT keyword syntax, we can name the constraint according to our chosen convention, rather than having InnoDB use a system assigned name.
That's the only difference.
(Confusingly, the syntax for dropping the foreign key constraint doesn't allow the CONSTRAINT keyword, we have to ALTER TABLE ... DROP FOREIGN KEY foo, where foo is the name of the foreign key constraint, whether we assigned the name or InnoDB generated it.)
Yes, InnoDB automatically creates an index to support the foreign key, if a suitable index isn't already available. If we define an index separately (using KEY indexname (id_parent) for example, then the foreign key constraint can have a different name than the index.
Related
I've created a table for accounts/users with a primary key (UsersID, AccountsID) like below. Should I add the index for the Users table?
create table AccountsUsers
(
AccountsID int unsigned not null,
UsersID int unsigned not null,
Roles bigint unsigned null,
primary key (UsersID, AccountsID),
constraint AccountsUsers_Accounts_ID_fk
foreign key (AccountsID) references Accounts (ID)
on update cascade on delete cascade,
constraint AccountsUsers_Users_ID_fk
foreign key (UsersID) references Users (ID)
on update cascade on delete cascade
)
engine=InnoDB
;
create index AccountsUsers_Accounts_ID_fk
on AccountsUsers (AccountsID)
;
MySQL will create the necessary indexes for the foreign key automatically, if necessary.
In the case of your foreign key on UsersId, it can use the left column of your primary key. It doesn't need to create a new index for that foreign key.
In the case of your foreign key on AccountsId, MySQL will create a new index automatically. It can't use the fact that AccountsId is part of your primary key, because it isn't the left-most column.
After you do the CREATE TABLE, run SHOW CREATE TABLE AccountsUsers and you should see the new index it created for AccountsId.
From the documentation
MySQL 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 index might be silently dropped later, if you create
another index that can be used to enforce the foreign key constraint.
index_name, if given, is used as described previously.
In other words, if you don't already have the required indexes on the columns of your referencing table (AccountsUsers), MySQL will create them for you.
If the columns in the referenced tables (Accounts and Users) are not indexed you will get an error. Your's look like they will be Primary Keys on their respective tables, so you should be fine.
I have a general question about constraint.
What are the difference between the following examples?
CREATE TABLE Orders (
OrderID int NOT NULL PRIMARY KEY,
OrderNumber int NOT NULL,
PersonID int FOREIGN KEY REFERENCES Persons(PersonID)
);
CREATE TABLE Orders (
OrderID int NOT NULL,
OrderNumber int NOT NULL,
PersonID int,
PRIMARY KEY (OrderID),
CONSTRAINT FK_PersonOrder FOREIGN KEY (PersonID)
REFERENCES Persons(PersonID)
);
Thank you!
There is no logical difference.
Standard SQL supports both forms of declaring constraints: at the column level, as in your first example, and at the table level, in your second example.
Table level constraint syntax is needed if you have a primary key or foreign key that involves more than one column.
MySQL supports both column-level and table-level syntax for PRIMARY KEY. But if you subsequently run SHOW CREATE TABLE Orders you will see that MySQL reports it back as if it was declared as a table-level constraint.
MySQL supports only table-level syntax for FOREIGN KEY.
It has been a long-time feature request to support column-level FOREIGN KEY syntax, but so far it has not been implemented. https://bugs.mysql.com/bug.php?id=4919
In the first example, The database will name the constraints implicitly.
In the second example, the create table statement sets the name of the foreign key constraint explicitly. (the primary key should also be named but it's not in this example)
As best practice, you should always give your constraints meaningful names.
CREATE TABLE `profilePic` (
`ClientID` VARCHAR(255) NOT NULL,
PRIMARY KEY (`ClientID`),
CONSTRAINT `FK__user_details` FOREIGN KEY (`ClientID`) REFERENCES `user_details` (`ClientID`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;
I am trying to add table with foreign key and I got this error, why that happend ?
trying doing new table.
i am trying to put same details on user_details->ClientID and profilePic->ClientID
3.i have already one table call`d userdb and in this table i have ClientID and its foreign key and its work.
The below will fail because the collation is different. Why do I show this? Because the OP didn't.
Note I shrunk the size due to error 1071 on sizing for varchar 255 with that collation and then auto chosen charset.
The point being, if collation is different, it won't work.
CREATE TABLE `user_details` (
`ClientID` VARCHAR(100) NOT NULL,
PRIMARY KEY (`ClientID`)
)ENGINE=InnoDB;
CREATE TABLE `profilePic` (
`ClientID` VARCHAR(100) NOT NULL,
PRIMARY KEY (`ClientID`),
CONSTRAINT `FK__user_details` FOREIGN KEY (`ClientID`) REFERENCES `user_details` (`ClientID`) ON UPDATE CASCADE ON DELETE CASCADE
)COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;
The above failure is at the table level. A trickier one causing a 1215 error due to column-level collation mismatches can be seen in This answer.
Pulling the discussion up to more general cases ...
whether you are trying to establish a Foreign Key constraint on table creation or with ALTER TABLE
| ADD [CONSTRAINT [symbol]]
FOREIGN KEY [index_name] (index_col_name,...)
reference_definition
such as
ALTER TABLE `facility` ADD CONSTRAINT `fkZipcode`
FOREIGN KEY (`zipcode`) REFERENCES `allzips`(`zipcode`);
the following will apply.
From the MySQL manual page entitled Using FOREIGN KEY Constraints:
Corresponding columns in the foreign key and the referenced key must
have similar data types. The size and sign of integer types must be
the same. The length of string types need not be the same. For
nonbinary (character) string columns, the character set and collation
must be the same.
In addition, the referenced (parent) table must have a left-most key available for fast lookup (verification). That parent key does not need to be PRIMARY or even UNIQUE. This concept is described in the 2nd chunk below. The first chunk alludes to a Helper index that will be created if necessary in the referencing (child) table if so necessary.
MySQL 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 index might be silently dropped later, if you create
another index that can be used to enforce the foreign key constraint.
index_name, if given, is used as described previously.
InnoDB permits a foreign key to reference any 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.
When trying to create a foreign key via HeidiSQL, you get a warning as soon as the selected column data types don't match. I added this warning to HeidiSQL's table designer due to the non-intuitive message from the server ("Cannot add foreign key constraint")
The selected foreign column do not match the source columns data type and unsigned flag. This will give you an error message when trying to save this change. Please compare yourself:
I'm attempting to setup a foreign key in table cell_lines that will reference the topographic_region column of the composite primary key in table topographic_regions.
Each time I run the last three lines of code trying to add the foreign key, I receive Error Code 1215: cannot add foreign key constraint.
Now, the foreign key column name (topographic_region) in cell_lines only matches one of the composite primary key column names in topographic_regions, the other composite primary key column name being topographic_region_id. Do I usually need to address both components of a composite primary key when creating a foreign key?
A follow up problem is that I've actually already tried addressing both components of a composite primary key using a composite foreign key constraint, and I was still presented with an Error Code 1215: cannot add foreign key constraint.
What can I do to solve this problem, and is there anymore information you would like me to provide in order to do so? I'm happy to respond.
Thanks for reading. I'm very new to mySQL.
create table topographic_regions(
topographic_regions_id int not null auto_increment,
topographic_region int(10),
karyotypes varchar(255),
constraint pk_topographicID primary key (topographic_regions_id, topographic_region)
);
create table cell_lines(
cell_lines_id int not null auto_increment,
cell_line varchar(50),
topographic_region int(10),
constraint pk_cellID primary key (cell_lines_id, cell_line)
);
alter table cell_lines
add foreign key (topographic_region)
references topographic_regions(topographic_region);
This is the problem with composite PKs. In fact, your autonumber topographic_region_id will be unique and you should use that for the PK, and the FK. topographic_region sounds like it is also unique so you should add a unique index to it.
A foreign key is some columns whose subrow values have to appear as subrow values in another table where they are a candidate key. If you really had a foreign key from cell_lines to topographic_regions then cell_lines would have a topographic_region_name column and you would need:
alter table cell_lines
add foreign key (topographic_regions_id, topographic_region)
references topographic_regions(topographic_regions_id, topographic_region);
I suspect that (topographic_regions_id, topographic_region) is not a candidate key of topographic_regions and that topographic_regions_id is enough to identify a region just because you decided cell_lines doesn't have a topographic_region column. Although it may be that a cell line doesn't identify a particular topographic region. But then topographic_regions_id is not a foreign key in cell_lines, since it isn't a key in topographic_regions. (There is no easy way in SQL to constrain that some columns' subrow values have to appear as subrow values in another table where they are not a superset of a candidate key.)
If topographic_regions_id is unique in topographic_regions then it is a candidate key and should be declared UNIQUE NOT NULL. If topographic_region_name is unique in topographic_regions then it is a candidate key and should be declared UNIQUE NOT NULL. If either is a candidate key then (topographic_regions_id, topographic_region) is not a candidate key. You can pick one candidate key to be declared PRIMARY KEY which just means UNIQUE NOT NULL. Ditto for cell_line. Since your _id columns are auto_increment, I suspect they are unique, in which case neither table has a composite candidate key.
(All this assuming none of your columns can be NULL.)
I'm very new to SQL, I'm trying to define a 2 tables Hospital and Hospital_Address but when I'm trying to add foreign key in Hospital_Address it throws an error: "1215: Cannot add foreign key"
create table Hospital (
HId Int not null,
HName varchar(40) not null,
HDept int, Hbed Int,
HAreaCd int not null,
Primary Key (HId)
);
create table Hospital_Address (
HAreaCd Int not null,
HArea varchar(40) not null,
HCity varchar(40),
HAdd1 varchar(40),
HAdd2 varchar(40),
Primary Key (HArea),
foreign key (HAreaCd) references Hospital (HAreaCd));
Please help me in this regard. Thanks in advance.
MySQL requires that there be an index on the HAreaCd column in the parent Hospital table, in order for you to reference that column in a FOREIGN KEY constraint.
The normative pattern is for the FOREIGN KEY to reference the PRIMARY KEY of the parent table, although MySQL extends that to allow a FOREIGN KEY to reference a column that is a UNIQUE KEY, and InnoDB extends that (beyond the SQL standard) and allows a FOREIGN KEY to reference any set of columns, as long as there is an index with those columns as the leading columns (in the same order specified in the foreign key constraint.) (That is, in InnoDB, the referenced columns do not need to be unique, though the behavior with this type of relationship may not be what you intend.)
If you create an index on that column in Hospital table, e.g.:
CREATE INDEX Hospital_IX1 ON Hospital (HAreaCd);
Then you can create a foreign key constraint that references that column.
However, because this is a non-standard extension of MySQL and InnoDB, the "best practice" (as other answers here indicate) is for a FOREIGN KEY to reference the PRIMARY KEY of the foreign table. And ideally, this will be a single column.
Given the existing definition of the Hospital table, a better option for a foreign key referencing it would be to add the Hid column to the Hospital_Address table
... ADD HId Int COMMENT 'FK ref Hospital.HId'
... ADD CONSTRAINT FK_Hospital_Address_Hospital
FOREIGN KEY (HId) REFERENCES Hospital (HId)
To establish the relationship between the rows, the values of the new HId column will need to be populated.
You cannot add a foreign key to a non-primary key element of another table usually.
If you really need to do so, refer to this question for help : Foreign Key to non-primary key
HAreaCd in the Hospital table should be a primary key. Only then can you reference it in the Hospital_Address table