I am in the process of designing the databases for my system. There are a lot of foreign key constraints.
I was wondering whether I could get some advice, whether I should do which of the following:
1) Specify the constraints during table creation itself ie,
CREATE TABLE IF NOT EXISTS abc
(
keyword VARCHAR(20) NOT NULL,
id INT UNSIGNED NOT NULL,
FOREIGN KEY (id) REFERENCES xyz(id) ON DELETE CASCADE ON UPDATE CASCADE
)ENGINE=InnoDB;
2)create the table without FK constraints and 'alter' the table later on ie,
CREATE TABLE IF NOT EXISTS abc
(
keyword VARCHAR(20) NOT NULL,
id INT UNSIGNED NOT NULL,
)ENGINE=InnoDB;
ALTER TABLE abc ADD CONSTRAINT fk_constraint FOREIGN KEY (id) REFERENCES xyz(id)
ON DELETE CASCADE ON UPDATE CASCADE;
Table xyz is simply another table with 'id' as a primary key.
You may create the FK at once. But this is not always possible because they can refer to each other in a circular fashion. Also, you may want to add columns later, with a FK.
It may be slightly faster to add it at once, because MySQL has to validate and rebuild the table structure for some changes (although I'm not sure adding FKs is one of those). But this process will be reasonably fast on empty tables, so it doesn't matter much when you add the FK.
The result will be the same. So, there is no differences.
If I create new database, I'd create table and its foreign key in one statement. The script will look better. But in this case parent tables must be created before the child tables.
If you don't want to take into account dependencies when creating tables, you can create tables in random order in the beginning of the script and then add foreign keys using ALTER TABLE.
Related
I'm relatively new to MySQL syntax. I'm trying to set up a database with different schemas. For convenience I structured my code in two parts:
in the first part I'm creating the tables in each schema without imposing foreign key constraints
in the second part I'm writing ALTER TABLE commands to create foreign key relations.
When it comes to create a foreign key constraint for an ID in a table that point to a table in another schema I get
"Error Code: 1824. Failed to open the referenced table 'schema_a.table_a".
Practically, I've done this:
#First part
CREATE SCHEMA `schema_a`
USE `schema_a`;
CREATE TABLE `table_a`
(
IDa INTEGER NOT NULL,
...
PRIMARY KEY(`IDa`)
)ENGINE=InnoDB, CHARSET=..., Collate=...;
CREATE SCHEMA `schema_b`
USE `schema_b`;
CREATE TABLE `table_b`
(
IDb INTEGER NOT NULL,
IDa INTEGER NOT NULL,
...
PRIMARY KEY(`IDb`)
)ENGINE=InnoDB, CHARSET=..., Collate=...;
#Second part
USE `Schema_b`;
ALTER TABLE `table_b`
ADD CONSTRAINT `FK_IDa` FOREIGN KEY (`IDa`) REFERENCES `schema_a.table_a`(`IDa`) ON DELETE CASCADE ON UPDATE CASCADE;
I'm not even sure if it is formally correct to create external foreign keys.
Does anyone have any suggestions to solve this problem?
Thanks!
`schema_a.table_a` means one identifier, i.e. MySQL assumes that only the table name is schema_a.table_a. You need to quote each part of a multi part identifier individually like in `schema_a`.`table_a`.
ALTER TABLE `table_b`
ADD CONSTRAINT `FK_IDa`
FOREIGN KEY (`IDa`)
REFERENCES `schema_a`.`table_a`
(`IDa`)
ON DELETE CASCADE
ON UPDATE CASCADE;
Or you can just not quote in your particular case.
I have searched questions about this problem:
Similar question 01
Similar question 02
but I find they are not similar to my case.
Here is my tables:
Table 1 history:
create table if not exists history(
worker_num int(11),
cust_num int(11),
primary key (cust_num,worker_num)
)engine=innodb, default charset=utf8;
Table 2 customer:
drop table if exists customer;
create table if not exists customer(
cust_number int(11) not null,
foreign key (cust_number) references history(cust_num)
)engine=innodb, default charset utf8;
Table 3 worker:
drop table if exists worker;
create table if not exists worker(
worker_number int(11) not null,
foreign key (worker_number) references history(worker_num)
)engine=innodb, default charset=utf8;
I can create Table 1 and Table 2 successfully. However, when I try to create Table 3, It throws me an error like below:
Failed to add the foreign key constraint. Missing index for constraint 'fk_customer' in the referenced table 'history
Error code 1822.'
Question 01:
I know this is the problem of index. Because I found that if I put the Table3 creating code before Table2, I cannot create Table 2 successfully.
Thus, I know it must be caused by when the Table3 calls
foreign key (worker_number) references history(worker_num)
it will try to find the first primary key, primary key (cust_num,worker_num), in Table1 as its corresponding primary.
However, the first primary key in table 1 is cust_num and this cust_num is not the correct corresponding primary key to foreign key worker_num. Thus, it throws an error.
However, I search official Mysql document and find the description of index. It says:
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.
Here, you can see that Such an index is created on the referencing table automatically.
So, I'm very curious about if the referencing table is created automatically, why we cannot create child tables in any orders?(in my case, why should I create table 2 first or I will fail creating tables?)
Question 2:
In my case, I want define a foreign key in each child tables(table 2 and table 3) references to the primary keys in parent table(table 1). How to solve this index problem?
Appreciate any helps!!!
Thanks!
You have to read the documentation carefully:
(...) Such an index is created on the referencing table automatically if it does not exist. (...)
Emphasis: me
That is, you get the error because a suitable index on the referenced table is missing, not on the referencing table. The latter maybe crated automatically but not the former.
It also looks like you reversed the foreign key logic. Assuming that customer should list all the customers, worker all the workers and history some relationship between customers and workers, probably who has worked for who, then cust_number and worker_number should be primary key in the respective tables and there should be no foreign key in customer nor worker. In history there should be two (separate) foreign keys, cust_num pointing to customer and worker_num pointing to worker. The primary key definition of history is OK.
I have two tables, and I've made a relation using the Designer between the id column of my first table to the user_id column of my second table. Where and how do I add code or do something so that when, for example, the parent (id) is deleted, the user_id values which correspond to the deleted id will also be deleted? I tried deleting one of the registered ids, but the corresponding rows in the child table didn't get deleted.
I've done some searching, but I'm still very confused.
Thank you.
Note: I'm experimenting with MySQL and PHP, and this is for a little blog I'm making.
Please add an ON DELETE referential action to the foreign key constraint.
More details could be found here:
https://dev.mysql.com/doc/refman/5.6/en/create-table-foreign-keys.html
For your case, ON DELETE CASCADE should be fine.
set id from first table as primary key
CREATE TABLE tbl_first(id INT PRIMARY KEY AUTO_INCREMENT, name varchar(20))
create your second table as tbl_second
CREATE TABLE tbl_second(id INT PRIMARY KEY AUTO_INCREMENT, fk_id int)
add constraint like this:
alter table tbl_second
add constraint fk_first
foreign key tbl_second(fk_id)
references tbl_first(id)
on delete cascade
it seem SQL Server and mySql are a little different, but it should work, i test it in mySQL
Using MySQL, moving from MyISAM to InnoDB tables. Database design started with dumping the data and re-importing it without foreign keys or constraints. Adding those one at a time to find errors.
I have ParentTable which can either be linked to ChildTableA or ChildTableB, but not both. Should the CREATE syntax be: (using CREATE syntax for simplicity rather than multiple ALTERs)
CREATE TABLE `ParentTable`
`IDParentTable` bigint(20) unsigned NOT NULL auto_increment,
`IDChildTableA` bigint(20) unsigned NOT NULL default '0',
`IDChildTableB` bigint(20) unsigned NOT NULL default '0',
PRIMARY KEY (`IDParentTable`),
KEY `ParentTable_IDChildTableA` (`IDChildTableA`),
KEY `ParentTable_IDChildTableB` (`IDChildTableB`)
ENGINE=InnoDB DEFAULT CHARSET=latin1;
Without thinking about it, I tried including:
CONSTRAINT `ParentTable_IDChildTableA` FOREIGN KEY (`IDChildTableA`) REFERENCES `ChildTableA` (`IDChildTableA`),
CONSTRAINT `ParentTable_IDChildTableB` FOREIGN KEY (`IDChildTableB`) REFERENCES `ChildTableB` (`IDChildTableB`)
Which failed, because many rows have 0 for IDChildTableA, and many rows have 0 for IDChildTableB. But, no rows have 0 for both. It's seeing that no ChildTableA exists with IDChildTableA of 0, and likewise with B.
Is there a proper way to handle this situation while keeping referential integrity? Without splitting ParentTable in two? A way to say it's OK if it's 0 or references a valid related table? Or, does wanting polymorphic tables mean I have to go without constraints?
BTW, I much prefer this route than having a single IDChildTable foreign key and then having another column designating whether it's table A or B... Not how I see that would work either for constraints, just saying I prefer not to go that route...
A column used as a foreign key can be nullable. Use a NULL value in the foreign key column to indicate "no row referenced."
It seems like you have your foreign keys backwards. Usually, the child table has a reference to the parent table.
parent (id int primary key)
childA (id int, parent_id int, ...)
childB (id int, parent_id int, ...)
EDIT
Related to the question regarding a foreign key column referencing two tables (based on a discriminator column)... that's not possible. A foreign key constraint can reference only one table.
To get something like that work, you'd need to add two separate foreign key columns, each referencing one target table. You could make use of the extra discriminator column (A or B) to identify which foreign key column should be used, so one fk column would be populated with a reference, the other fk column would be set to NULL.
However, there is no declarative constraint that would require exactly one of those two fk columns to be populated. That would not be enforced by the database. The extra discriminator column would actually be redundant, because you could derive that based on which foreign key column was populated.
Hi I'm pretty new to mysql and have tried some of the other suggested fixes for this problem but had no luck! I'm trying to create a foreign key between the tables application and customer but when i run my program I get the error "cannot add or update a child row a foreign key constraint fails mysql". My program is a data capture form and is meant to insert the information into the database.
Table Schemas:
application table:
applicationid mediumint(9)
covertype varchar(100)
customeremail varchar(100)
customertable:
customeremail varchar(100)
customerfname varchar(100)
applicationid mediumint(9)
I tried to set up a foreign key a few different ways e.g.
alter table application add foreign key(customeremail) references customer(customeremail)
alter table customer add foreign key (applicationid) references application(applicationid)
But this didn't work i'd appreciate any advice on how to solve the issue
You should try that syntax:
alter table application
add foreign key(customeremail)
references application(applicationid)
That means, a value in column customeremail from table application is only allowed if there is the same value in the column applicationid of (at least) one row of the table application.
Depending your background, you could think to that as a "pointer" -- but is relational algebra relations are bidirectional.
In addition, for this to work, you must have an index on the target. Here on application.applicationid. If this in not the case, you should write:
alter table application add index (applicationid)
My guess is this shouldn't be necessary since there is great chances that applicationid is your PRIMARY KEY.
BTW, as Stephan suggested it in comment, and since you are "pretty new to DB" you should definitively take a look at proper documentation about database normalization and referential integrity.