Foreign Key in SQL
A foreign key is a column (or a set of columns) in one table (child table) that uniquely identifies a row in another table(parent table). Foreign keys play a critical role for establishing and maintaining relationships between tables. They enforce referential integrity, ensuring the consistency and accuracy of data relationships.
A foreign key establishes a link between two tables by referencing the primary key (or a unique key) in another table. The table that contains the primary key is called the parent table, and the table that contains the foreign key is known as the child table. In this article, we will explore all aspects of foreign keys. By the end, you will have a clear understanding of foreign keys, including their syntax, use cases and key concepts etc.
Syntax
CREATE TABLE TableName ( Column1 DataType, Column2 DataType, FOREIGN KEY (Column1 ) REFERENCES ParentTableName(ParentColumnName) );
ALTER TABLE TableName ADD CONSTRAINT ConstraintName FOREIGN KEY (ColumnName) REFERENCES ParentTableName(ParentColumnName);
1. Defining a Foreign Key During Table Creation
a. Without Naming the Constraint
CREATE TABLE TableName ( Column1 DataType, Column2 DataType, FOREIGN KEY (Column1 ) REFERENCES ParentTableName(ParentColumnName) );
b. With Naming the Constraint
CREATE TABLE TableName ( Column1 DataType, Column2 DataType, CONSTRAINT FK_Name FOREIGN KEY (Column1 ) REFERENCES ParentTableName(ParentColumnName) );
- Explicitly assigns a user-defined name to the foreign key constraint.
- This is useful for referencing the constraint later, such as when altering or dropping the constraint.
Example
Let’s create two table Departments and Employees. Crate Departments table query :-
CREATE TABLE Departments ( Id INT PRIMARY KEY, Name VARCHAR(100) );
Create Employees table query with foreign key on Departments table on column DepartmentId
CREATE TABLE Employees ( EmployeeId INT PRIMARY KEY, Name VARCHAR(100), Mobile VARCHAR(15), DepartmentId INT, JobTitle VARCHAR(50), Salary DECIMAL(10, 2), CONSTRAINT FK_Department FOREIGN KEY (DepartmentId) REFERENCES Departments(Id) );
Verification
We have created a Foreign Key Constraint on a column DepartmentId in the Employees table that references the column named Id of the Departments table. So if you attempt to drop table Departments before dropping table Employees, the database will throw an error
DROP TABLE Departments;
Error Code: 3730. Cannot drop table 'Departments' referenced by a foreign key constraint 'FK_Department' on table 'Employees'. 0.000 sec
2. Adding a Foreign Key to an Existing Table
ALTER TABLE TableName ADD CONSTRAINT ConstraintName FOREIGN KEY (ColumnName) REFERENCES ParentTableName(ParentColumnName);
Example
Consider a case, if Employees table already exists and you need to add Foreign Key Constraint on DepartmentId then the query would be as follows
ALTER TABLE Employees ADD CONSTRAINT FK_DepartmentId FOREIGN KEY (DepartmentId) REFERENCES Departments (Id);
Indexes with Foreign Key
Different database systems handle the creation of indexes for foreign keys in different ways. In some databases, the index may be automatically created when you add the foreign key constraint. However, if it's not created automatically, you can manually create an index on the foreign key column for better performance.
MySQL and SQL Server automatically create indexes for foreign keys, while PostgreSQL, Oracle and SQLite do not. You need to create the index manually if required for performance.
Q. Is it possible to use a column of the parent table, which is neither a primary key nor a unique key, as a foreign key in the child table?
Ans. No, you can not use a column in the parent table that is neither a primary key nor a unique key as a foreign key in the child table. Because if the parent column is not unique, it could have multiple rows with the same value, leading to ambiguity and breaking referential integrity. Therefore, only columns with a primary key or unique constraint can be referenced by foreign keys. If you attempt to add , the database will throw an error.
Example
CREATE TABLE Departments ( Id INT PRIMARY KEY, Name VARCHAR(100) ); CREATE TABLE Employees ( EmployeeId INT PRIMARY KEY, Name VARCHAR(100), Mobile VARCHAR(15), DepartmentId INT, JobTitle VARCHAR(50), Salary DECIMAL(10, 2), CONSTRAINT FK_Department FOREIGN KEY (Name) REFERENCES Departments(Name) );
Error Code: 1822. Failed to add the foreign key constraint. Missing index for constraint 'FK_Department' in the referenced table 'departments'. 0.016 sec
Key Points of Foreign Key
- Foreign keys can be defined at the time of table creation or added later to an existing table.
- Foreign keys enforce referential integrity. This ensures that relationships between data are valid and consistent.
- The foreign key column in the child table points to the primary key or a unique key in the parent table. This key is usually the primary key of the parent table but can also be a unique key if needed.
- While a foreign key can reference any unique field (including a unique key), it's typically used to reference a primary key in relational databases.
- A table can have multiple foreign keys, each referencing different tables or columns within same table, It is useful for establishing many relationships with other tables
- While foreign keys are essential for data integrity but they can introduce some performance overhead during insert, update and delete operations due to the need to check the foreign key constraints.
- Proper indexing and foreign key management can significantly improve data consistency and query performance.
- Primarily for Foreign Keys: CASCADE, SET NULL, NO ACTION and RESTRICT are options used within foreign key constraints to manage the behavior when the parent record is updated or deleted.
ON DELETE / ON UPDATE Options
These options control what happens to the child table when the parent row is deleted or updated.
Option | What It Does (Simplified) | Example Scenario |
---|---|---|
CASCADE | Automatically deletes or updates related child rows. | If a user is deleted from the Users table, all their posts in the Posts table will also be deleted. |
SET NULL | Sets the foreign key in the child table to NULL. | If a manager is removed from the Employees table, the manager_id in the Departments table becomes NULL. |
RESTRICT | Blocks the delete/update if any related child rows exist. | You can’t delete a category from the Categories table if any products are still linked to it in the Products table. |
NO ACTION | Like RESTRICT, but the check is deferred (happens at the end of the transaction in some databases). | Similar to RESTRICT, but may allow complex logic in a single transaction before enforcing rules. |
Quick Explanation
- Use CASCADE when you want related rows to follow the parent automatically (good for things like user posts, orders etc.).
- Use SET NULL when it's okay for child rows to exist without a parent (like optional relationships).
- Use RESTRICT or NO ACTION when you want to protect child data from being orphaned or invalid.
SQL Syntax Example
-- CASCADE Example FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE; -- SET NULL Example FOREIGN KEY (manager_id) REFERENCES employees(id) ON DELETE SET NULL; -- RESTRICT Example FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE RESTRICT;
FAQs
Q1. What is the purpose of a foreign key?
A foreign key ensures referential integrity between two tables by linking the child table to a primary or unique key in the parent table. It ensures that the value in the child column exists in the parent column.
Q2. Can a table have more than one foreign key?
Yes. A table can have multiple foreign keys, each referencing a different table or even different columns in the same table.
Q3. Can a foreign key reference a non-primary key column?
Yes, but only if that column has a UNIQUE constraint. A foreign key must reference a column that is either a primary key or unique key to ensure unambiguous relationships.Q4. What happens if I try to insert a value in the child table that doesn’t exist in the parent table?
The insert will fail with a referential integrity constraint violation. The database will not allow orphan records that don’t have corresponding entries in the parent table.
Q5. How can I remove a foreign key constraint?
Use the ALTER TABLE statement with DROP CONSTRAINT
ALTER TABLE TableName DROP FOREIGN KEY ConstraintName; -- MySQL -- or ALTER TABLE TableName DROP CONSTRAINT ConstraintName; -- SQL Server, PostgreSQL
Q6. Do foreign keys automatically create indexes?
It depends on the database system you are using. Here is how some major databases handle it
Database | Creates Index Automatically? | Explanation |
---|---|---|
MySQL | ✅ Yes | When you create a foreign key, MySQL automatically creates an index on the foreign key column (if it doesn't already exist). |
SQL Server | ✅ Yes | SQL Server also automatically creates an index to support the foreign key constraint. |
PostgreSQL | ❌ No | You must manually create an index on the foreign key column to improve performance, especially for joins and deletes. |
Oracle | ❌ No | Oracle enforces the foreign key constraint but does not create an index. You should create it yourself for better performance. |
SQLite | ❌ No | SQLite supports foreign keys but does not automatically index them. Manual indexing is recommended. |
Q7. What are cascading actions in foreign keys?
Cascading actions define how changes in the parent table affect the child table
- ON DELETE CASCADE: Deletes child rows when the parent row is deleted.
- ON UPDATE CASCADE: Updates child rows when the parent key changes.
- SET NULL: Sets the child foreign key column to NULL.
- RESTRICT / NO ACTION: Prevents the parent row from being updated or deleted if related child rows exist.
Q8. Can a foreign key reference multiple columns (composite key)?
Yes, A foreign key can reference composite keys, as long as the combination of columns in the parent table is a primary or unique key and the same number and type of columns are used in the child table.
Q9. Can foreign keys be self-referencing?
Yes, A table can have a self-referencing foreign key, where a column refers to another row in the same table. This is useful for hierarchies like employee-manager relationships.
ExampleCREATE TABLE Employees ( Id INT PRIMARY KEY, Name VARCHAR(100), ManagerId INT, FOREIGN KEY (ManagerId) REFERENCES Employees(Id) );
Q10. What is the difference between a primary key and a foreign key?
Feature | Primary Key | Foreign Key |
---|---|---|
Purpose | Uniquely identifies each record in the table | Creates a link between two tables (child → parent) |
Allows NULLs | ❌ No – cannot be NULL (every row must have a value) | ✅ Yes – can be NULL (if no strict relationship is required) |
Must Be Unique | ✅ Yes – no two rows can have the same value | ❌ No – can have duplicate values |
References Other Table? | ❌ No – stands on its own | ✅ Yes – must reference a primary (or unique) key in another table |
Number per Table | ✅ Only one per table | ✅ Can have multiple foreign keys in one table |
Q11. Can a foreign key column have NULL values?
Yes, A foreign key column can be NULL, meaning the relationship is optional. However, if the column is declared as NOT NULL, then a valid reference must exist in the parent table.
Q12. What is a circular foreign key dependency?
A circular foreign key dependency happens when two or more tables reference each other through foreign keys, either directly or indirectly.
This creates a loop in the relationships, making it tricky to insert, update or delete records because the operations depend on each other.
Example (Direct Circular Dependency)-- Table A references Table B CREATE TABLE A ( id INT PRIMARY KEY, b_id INT, FOREIGN KEY (b_id) REFERENCES B(id) ); -- Table B references Table A CREATE TABLE B ( id INT PRIMARY KEY, a_id INT, FOREIGN KEY (a_id) REFERENCES A(id) );
- You can't insert a row into A without a valid row in B.
- But you also can't insert into B without a valid row in A.
- This creates a deadlock unless you use special handling.
Q13. How to Handle Circular foreign key Dependencies
Circular foreign key dependencies can make insertions, updates, and deletions difficult because the tables rely on each other. To handle them safely and efficiently, you can use one or more of the following strategies
1. Use Deferred Constraints (If Supported)
Postpone foreign key checks until the end of the transaction. This allows both rows to be inserted before enforcing the constraint.
Supported in: PostgreSQL, Oracle
-- PostgreSQL Example ALTER TABLE A ADD CONSTRAINT fk_b FOREIGN KEY (b_id) REFERENCES B(id) DEFERRABLE INITIALLY DEFERRED;
2. Insert NULLs First, Then Update
Insert records with NULL values for the foreign key columns first, then update them after both rows exist.
-- Step 1: Insert A and B with NULL foreign keys INSERT INTO A (id, b_id) VALUES (1, NULL); INSERT INTO B (id, a_id) VALUES (10, 1); -- Step 2: Update A with B's ID UPDATE A SET b_id = 10 WHERE id = 1;
3. Temporarily Disable Foreign Keys (With Caution)
Disable constraints during data load/migration, then re-enable them afterward.
⚠️ Warning: Only safe if you're 100% sure your data is valid.
-- Example in MySQL SET foreign_key_checks = 0; -- perform inserts SET foreign_key_checks = 1;
4. Refactor the Schema (Recommended)
Best long-term solution: Avoid circular dependencies by redesigning the database structure.
Method | When to Use |
---|---|
Deferred Constraints | If the DB supports it and you need strong integrity |
Insert NULL, then Update | Works in all databases; good for tight circular refs |
Temporarily Disable FKs | Use during data migration with caution |
Schema Refactoring | Best for long-term maintainable design |
Q14. What error do I get if a foreign key constraint is violated?
When you try to insert, update or delete data that violates a foreign key constraint, your database will throw an error to prevent invalid relationships. Common error messages include
MySQLError Code: 1452. Cannot add or update a child row: a foreign key constraint fails
ERROR: insert or update on table "child_table" violates foreign key constraint "child_table_fk" DETAIL: Key (parent_id)=(999) is not present in table "parent_table".
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Child_Parent". The conflict occurred in database "YourDB", table "dbo.Parent", column 'id'.
Q15. Can I disable foreign key checks temporarily?
Yes, in many (but not all) database systems you can temporarily disable foreign key enforcement , though the commands and support vary.
MySQLSET FOREIGN_KEY_CHECKS = 0; -- Disable -- Perform operations SET FOREIGN_KEY_CHECKS = 1; -- Re-enable
ALTER TABLE TableName NOCHECK CONSTRAINT ALL; -- To re-enable: ALTER TABLE TableName WITH CHECK CHECK CONSTRAINT ALL;
Q16. How can I find foreign key constraints on a table?
You can easily retrieve foreign key information using built-in system views or commands in major databases. Here are effective methods for each:
MySQLSELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_NAME = 'your_table_name' AND REFERENCED_TABLE_NAME IS NOT NULL;
Alternatively, simply run below query to view any defined foreign key constraints in the table creation statement.
SHOW CREATE TABLE your_table_name;
EXEC sp_fkeys 'your_table_name';
SELECT conname, confrelid::regclass AS parent_table FROM pg_constraint WHERE conrelid = 'your_table_name'::regclass AND contype = 'f';
Q17. Can I update a referenced key in the parent table?
Yes, in some cases but it depends on how the foreign key constraint is defined.
- You can update a parent key only if it's defined with ON UPDATE CASCADE or there are no referencing rows.
- When ON UPDATE CASCADE is in effect, updating the parent table automatically updates matching foreign key values in child tables.
- If ON UPDATE CASCADE is not specified and there are existing child rows referencing that key, the update will fail with a referential integrity violation.
- Many databases (e.g., MySQL, SQL Server) by default use NO ACTION or RESTRICT for update rules, which block updates when dependent rows exist.
Q18. How does a foreign key affect DELETE operations?
By default, if a referenced row exists in the child table, deleting it in the parent table is blocked. You can control behavior using
- ON DELETE CASCADE – Deletes child rows automatically.
- ON DELETE SET NULL – Sets child foreign key column to NULL.
- ON DELETE RESTRICT or NO ACTION – Prevents deletion if related rows exist.
Q19. Can I create a foreign key on a computed or expression column?
No, Foreign keys must reference real, persistent columns, not derived or computed ones.
Q20. When should I avoid foreign keys?
While foreign keys are important for data integrity, you may avoid them in following cases
- High-throughput systems where constraint checks add overhead
- Data warehousing (ETL) environments where constraints are handled by logic.
- Applications where relationships are enforced at the application level rather than database level.
1. High-Throughput OLTP or Microservices Environments
- Every INSERT, UPDATE, DELETE with foreign keys incurs additional integrity checks. In high-concurrency systems with very frequent writes, this can introduce latency or lock contention.
- It is checked by some developer that importing large data sets took minutes with FKs and only seconds when constraints were disabled.
2. Bulk Loading or ETL Pipelines / Data Warehousing
- In data warehouse workflows, constraints are often handled in SQL/ETL logic rather than enforced in the database.
- Disabling or avoiding foreign keys is common to speed up batch loading. In some ETL approaches, relationships are documented but constraints aren't enforced at runtime.
3. Application-Level Integrity Enforcement
- Some teams handle relational integrity in application code instead of relying on database-level constraints. This avoids database overhead—but often results in increased coding complexity and potential for bugs.
4. Simplified or Evolving Schema Needs
- Scenarios involving frequent schema redesign, partitioning or ad-hoc migrations may suffer complexity when foreign keys are present.
- Foreign keys can restrict schema changes and slow down migrations.