I'm setting up a database using phpMyAdmin. I have two tables (foo and bar), indexed on their primary keys. I am trying to create a relational table (foo_bar) between them, using their primary keys as foreign keys.
I created these tables as MyISAM, but have since changed all three to InnoDB, because I read that MyISAM doesn't support foreign keys. All id fields are INT(11).
When I choose the foo_bar table, click the "relation view" link, and try to set the FK columns to be database.foo.id and database.bar.id, it says "No index defined!" beside each column.
What am I missing?
Clarification/Update
For the sake of simplicity, I want to keep using phpMyAdmin. I am currently using XAMPP, which is easy enough to let me focus on the PHP/CSS/Javascript, and it comes with phpMyAdmin.
Also, although I haven't been able to set up explicit foreign keys yet, I do have a relational table and can perform joins like this:
SELECT *
FROM foo
INNER JOIN foo_bar
ON foo.id = foo_bar.foo_id
INNER JOIN bar
ON foo_bar.bar_id = bar.id;
It just makes me uncomfortable not to have the FKs explicitly defined in the database.
If you want to use phpMyAdmin to set up relations, you have to do 2 things. First of all, you have to define an index on the foreign key column in the referring table (so foo_bar.foo_id, in your case). Then, go to relation view (in the referring table) and select the referred column (so in your case foo.id) and the on update and on delete actions.
I think foreign keys are useful if you have multiple tables linked to one another, in particular, your delete scripts will become very short if you set the referencing options correctly.
EDIT: Make sure both of the tables have the InnoDB engine selected.
phpMyAdmin lets you define foreign keys using their "relations" view. But since, MySQL only supports foreign constraints on "INNO DB" tables, the first step is to make sure the tables you are using are of that type.
To setup a foreign key so that the PID column in a table named CHILD references the ID column in a table named PARENT, you can do the following:
For both tables, go to the operations tab and change their type to "INNO DB"
Make sure ID is the primary key (or at least an indexed column) of the PARENT table.
In the CHILD table, define an index for the PID column.
While viewing the structure tab of the CHILD table, click the "relation view" link just above the "add fields" section.
You will be given a table where each row corresponds to an indexed column in your CLIENT table. The first dropdown in each row lets you choose which TABLE->COLUMN the indexed column references. In the row for PID, choose PARENT->ID from the dropdown and click GO.
By doing an export on the CHILD table, you should see a foreign key constraint has been created for the PID column.
This is a summary of a Wikipedia article. It specifies the different types of relationships you can stipulate in PHPmyadmin. I am putting it here because it is relevant to #Nathan's comment on setting the foreign keys options for "on update/delete" but is too large for a comment.
CASCADE
Whenever rows in the master (referenced) table are deleted (resp. updated), the respective rows of the child (referencing) table with a matching foreign key column will get deleted (resp. updated) as well. This is called a cascade delete (resp. update[2]).
RESTRICT
A value cannot be updated or deleted when a row exists in a foreign key table that references the value in the referenced table. Similarly, a row cannot be deleted as long as there is a reference to it from a foreign key table.
NO ACTION
NO ACTION and RESTRICT are very much alike. The main difference between NO ACTION and RESTRICT is that with NO ACTION the referential integrity check is done after trying to alter the table. RESTRICT does the check before trying to execute the UPDATE or DELETE statement. Both referential actions act the same if the referential integrity check fails: the UPDATE or DELETE statement will result in an error.
SET NULL
The foreign key values in the referencing row are set to NULL when the referenced row is updated or deleted. This is only possible if the respective columns in the referencing table are nullable. Due to the semantics of NULL, a referencing row with NULLs in the foreign key columns does not require a referenced row.
SET DEFAULT
Similar to SET NULL, the foreign key values in the referencing row are set to the column default when the referenced row is updated or deleted.
In phpmyadmin, you can assign Foreign key simply by its GUI. Click on the table and go to Structure tab. find the Relation View on just bellow of table (shown in below image).
You can assign the forging key from the list box near by the primary key.(See image below). and save
corresponding SQL query automatically generated and executed.
For those new to database .... and need to ALTER an existing table. A lot things seem to be pretty straightforward, but there is always something ... between A and B.
Before anything else, take a look at this.
Make sure you have P_ID (parent ID on both parent and child table).
Of course it will be already filled in the parent. Not necessarily in the child in a true and final way. So for instance P_ID #3 (maybe many times in the child table will be pointing to original P_ID at parent table).
Go to SQL tab (I am using phpMyAdmin, should be similar in other ones) and do this command:
ALTER TABLE child_table_name
ADD FOREIGN KEY (P_ID)
REFERENCES parent_table_name (P_ID)
Click on child table, than structure, finally on relational view. Finish your DB planning there. There was a nice answer before this one about cascade, restrict, etc.
Of course it could be done by commands...
Foreign key means a non prime attribute of a table referes the prime attribute of another
*in phpMyAdmin* first set the column you want to set foreign key as an index
then click on RELATION VIEW
there u can find the options to set foreign key
InnoDB allows you to add a new foreign key constraint to a table by using ALTER TABLE:
ALTER TABLE tbl_name
ADD [CONSTRAINT [symbol]] FOREIGN KEY
[index_name] (index_col_name, ...)
REFERENCES tbl_name (index_col_name,...)
[ON DELETE reference_option]
[ON UPDATE reference_option]
On the other hand, if MyISAM has advantages over InnoDB in your context, why would you want to create foreign key constraints at all. You can handle this on the model level of your application. Just make sure the columns which you want to use as foreign keys are indexed!
Don't forget that the two columns should have the same data type.
for example if one column is of type INT and the other is of type tinyint you'll get the following error:
Error creating foreign key on [PID column] (check data types)
This is old thread but answer because if useful to anyone.
Step 1. Your Db Storage Engine set to InnoDB
Step 2. Create Primary Table
here customer is primary table and customer_id is primary key
Step 3. create foreign key table and give index
here we have customer_addresses as related table and store customer addresses, so here customer_id relation with customer table
we can select index directly when create table as below
If you forgot to give index when create a table, then you can give index from the structure tab of table as below.
Step 4. Once index give to the field, Go to structure tab and click on Relation View as shown in below pic
Step 5. Now select the ON DELETE and ON UPDATE what you want to do, Select column from current table, select DB (SAME DB), select relation table and primary key from that table as shown in below pic and Save it
Now check if relation are give successfully, go to foreign table data list and click on foreign key value, you will redirect to primary table record, then relation made successfully.
Make sure you have selected your mysql storage engine as Innodb and not MYISAM as Innodb storage engine supports foreign keys in Mysql.
Steps to create foreign keys in phpmyadmin:
Tap on structure for the table which will have the foreign key.
Create INDEX for the column you want to use as foreign key.
Tap on Relation view, placed below the table structure
In the Relation view page, you can see select options in front of the field (which was made an INDEX).
UPDATE CASCADE specifies that the column will be updated when the referenced column is updated,
DELETE CASCADE specified rows will be deleted when the referenced rows are deleted.
Alternatively, you can also trigger sql query for the same
ALTER TABLE table_name
ADD CONSTRAINT fk_foreign_key_name
FOREIGN KEY (foreign_key_name)
REFERENCES target_table(target_key_name);
Step 1:
You have to add the line:
default-storage-engine = InnoDB
under the [mysqld] section of your mysql config file (my.cnf or my.ini depending on your OS) and restart the mysqld service.
Step 2:
Now when you create the table you will see the type of table is: InnoDB
Step 3:
Create both Parent and Child table. Now open the Child table and select the column U like to have the Foreign Key:
Select the Index Key from Action Label as shown below.
Step 4:
Now open the Relation View in the same child table from bottom near the Print View as shown below.
Step 5:
Select the column U like to have the Foreign key as Select the Parent column from the drop down.
dbName.TableName.ColumnName
Select appropriate Values for ON DELETE and ON UPDATE
First set Storage Engine as InnoDB
then the relation view option enable in structure menu
You can also do it with a SQL command, like so.
ALTER TABLE employees
ADD CONSTRAINT fk_companyid FOREIGN KEY (companyid)
REFERENCES companies (id)
ON DELETE CASCADE;
In this example, if a row from companies is deleted, all employees with that companyid are also deleted.
From the official MySQL documentation at https://dev.mysql.com/doc/refman/8.0/en/create-table-foreign-keys.html:
MySQL requires indexes on foreign keys and referenced keys so that
foreign key checks can be fast and not require a table scan.
Related
I have a table for resources which contains resources like case studies, whitepapers, webinars etc.
It has one to many relationship with another table case_study_blocks. So there is a foreign key caseStudyId in the case_study_blocks table, which points to case studies in the resources table.
I want to move all the case studies to a separate table case_studies, but to do that I'll also have to update the foreign key reference in the case_study_blocks table and make all the records there point to the newly generated unique ids in case_study table.
What is the correct way to migrate the complete data while preserving the relationship?
One way I can think of:
Drop foreign key constraint on case_study_blocks
Add new foreign key constraint on the caseStudyId column, pointing to the id column in case_studies table
But now how do I map the existing case_study_blocks correctly to the new IDs in case_studies table?
Perform the steps as follows:
Copy the relevant data (related to case studies) to the new case_studies table, including the original ID value -- which could be called oldCaseStudyId -- so that the case_studies table will have the newly generated ID (caseStudyId), and the original ID in a separate oldCaseStudyId column. The latter can be dropped when all is done.
Drop the existing foreign key constraint on case_study_blocks.caseStudyId
Perform the update of the caseStudyId values by the mapping that is now available in case_studies (it has both the old and new ID values). The SQL statement could look something like this:
update case_study_blocks
inner join case_studies on case_studies.oldCaseStudyId = case_study_blocks.caseStudyId
set case_study_blocks.caseStudyId = case_studies.caseStudyId;
Create the replacing foreign key constraint on case_study_blocks.caseStudyId
Delete the original rows from resources that relate to case studies
Drop the column case_study_blocks.oldCaseStudyId
I have a users table and other tables such as services, orders, etc... that are I would like to turn into child tables of the users table.
So far it's simple, I just add Foreign Key Constraint between users(id) and orders(user_id). But what if I'd like to add a Boolean users(disabled) field, that would cascade the update to the orders(disabled) and services(disabled) fields in the rows that reference the respective row in users via (user_id) key?
Would it work if I create a reference in the child table to the parent table using 2 keys, one primary and one non unique?
You could have probably answered your question yourself if you'd have tried it. Basically, you can't create a foreign key relation on columns that are not part of a primary key on the foreign table (as the name implies).
So, unless the disabled column is part of the primary key on the users table, then, no, you won't be able to create a foreign key relation in another table that would include the disabled column.
All is not lost though. You could use triggers to trigger the disabling of orders and services when a user becomes disabled.
I created my MySQL database using phpMyAdmin 3.5.8.1deb1 in Ubuntu.
Instead of that all my tables are InnoDB, I can't add a foreign key, and this is an example:
ALTER TABLE element ADD CONSTRAINT FK_element_id_user FOREIGN KEY (id_user) REFERENCES user(id) ON DELETE SET NULL ON UPDATE CASCADE;
When I run this script I get this error :
#1005 - Can't create table 'tpw.#sql-4d8_e2' (errno: 150) (Details...)
When I click on details I get this :
InnoDB Documentation Supports transactions, row-level locking, and foreign keys
I tried to add the FK manually in the relation view
There could be a couple of things going one here. Here are some things to look for:
Do the data types of each field between the tables match?
Are both both tables using the same MySQL engine?
Here is a good resource to help you debug this issue further.
Excerpt from the resource linked to above:
1) The two key fields type and/or size is not an exact match. For example, if one is INT(10) the key field needs to be INT(10) as well and not INT(11) or TINYINT. You may want to confirm the field size using SHOW CREATE TABLE because Query Browser will sometimes visually show just INTEGER for both INT(10) and INT(11). You should also check that one is not SIGNED and the other is UNSIGNED. They both need to be exactly the same.
2) One of the key field that you are trying to reference does not have an index and/or is not a primary key. If one of the fields in the relationship is not a primary key, you must create an index for that field.
3) The foreign key name is a duplicate of an already existing key. Check that the name of your foreign key is unique within your database. Just add a few random characters to the end of your key name to test for this.
4) One or both of your tables is a MyISAM table. In order to use foreign keys, the tables must both be InnoDB. (Actually, if both tables are MyISAM then you won’t get an error message – it just won’t create the key.) In Query Browser, you can specify the table type.
5) You have specified a cascade ON DELETE SET NULL, but the relevant key field is set to NOT NULL. You can fix this by either changing your cascade or setting the field to allow NULL values.
6) Make sure that the Charset and Collate options are the same both at the table level as well as individual field level for the key columns.
7) You have a default value (ie default=0) on your foreign key column.
8) One of the fields in the relationship is part of a combination (composite) key and does not have it’s own individual index. Even though the field has an index as part of the composite key, you must create a separate index for only that key field in order to use it in a constraint.
9) You have a syntax error in your ALTER statement or you have mistyped one of the field names in the relationship.
10) The name of your foreign key exceeds the max length of 64 chars.
User.ID has to be declared as an INDEX
Suppose I have a table named Suppliers and I want to delete the first row:
delete from suppliers where supplierID = 1
What does it mean to, "Do whatever is necessary to maintain consistency" after the prior query? The Primary Key (SupplierID) was created using the AUTO_INCREMENT.
Well if you are using AUTO_INCREMENT then you cant do what you are thinking as AUTO_INCREMENT keys in database are used to uniquely identify a given row. The best what you can do to find the lowest unused key value is that don't use AUTO_INCREMENT at all, and manage your keys manually.
Also to mention that you can use ON DELETE CASCADE to automatically delete the dependent records in InnoDB database however in MyISAM you have to manually delete them.
Also check this reference.
To maintain cosistency you should use InnoDB endine and foreign keys in dependent tables pointing to Suppliers.supplierID.
Then database will issue an error if you will try to delete record which is referenced in any other table.
http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
ID of first supplier can be found this way:
SELECT MIN( supplierID ) FROM Suppliers
The below set of commands:
alter table opportunities add column ownerId int null;
alter table opportunities add foreign key (ownerId) references users (id) on delete set null on update cascade;
Yields an error like this:
Error in foreign key constraint of table taous/#sql-318c_27:
There is no index in table "taous"."#sql-318c_27" where the columns appear
as the first columns. Constraint:
foreign key (ownerId) references users (id) on delete set null on update cascade
;
So I understand that an index is lacking on the referenced column
Now, the mysql documentation for foreign key constraints states:
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.
I run mysql 5.1 (xampp, windows) So I expect the columns to be indexed automatically on creation of a foreign key.
Any idea why can the auto indexing fail?
One more point:
The error only happens when the sql commands are run through PDO (a db update tool). When run directly in mysql console, no problems.
Thanks
Gidi
My understanding is that the auto-indexing is on the referencing table and not the referenced table.
In your case, the auto-indexing would add an index to ownerId in opportunities... except it doesn't need to, since you already did this.
I don't quite understand where "taous"."#sql-318c_27" comes from, but assuming that it relates to the users table, I believe the error is complaining that id is not indexed.
Another cause of this error could be that the types of the the referenced and referencing table columns do not match.
For example if the the ownerId column of the opportunities table is an INT but the Id column of the users is any type other than INT
That doesn't explain why it would work with the console and not a PDO however, but maybe this helps someone else down the line.