PostgreSQL: How to add/update foreign key in an existing table

Updated: January 5, 2024 By: Guest Contributor Post a comment

Introduction

Managing database relationships is a fundamental aspect of SQL databases. In PostgreSQL, modifying foreign key constraints in existing tables is a common administrative task, essential for maintaining data integrity. This tutorial walks through the steps to add and update foreign keys with practical examples.

Understanding Foreign Keys

Before diving into the process of modifying foreign keys, it’s important to understand what they are and why we use them. A foreign key is a column or a combination of columns used to establish a link between the data in two tables. This link ensures referential integrity of the data and enforces the relationship between tables by dictating that a value in one table must be present in the other. In PostgreSQL, foreign keys help to maintain consistent and reliable relationships between datasets.

Adding a Foreign Key to an Existing Table

Here’s how you add a foreign key constraint to an existing table:

ALTER TABLE child_table
ADD CONSTRAINT fk_name
FOREIGN KEY (column1) REFERENCES parent_table(column2);

This command adds a new constraint named fk_name to child_table establishing that column1 will act as the foreign key referencing column2 of the parent_table.

Example: Adding a Basic Foreign Key

ALTER TABLE order_items
ADD CONSTRAINT fk_order
FOREIGN KEY (order_id) REFERENCES orders(id);

This example adds a foreign key to the order_items table, tying the order_id column to the id column of the orders table.

Updating or Changing a Foreign Key

Updating a foreign key involves two steps: dropping the existing constraint and then adding a new one in its place:

ALTER TABLE child_table
DROP CONSTRAINT old_fk_name;
ALTER TABLE child_table
ADD CONSTRAINT new_fk_name
FOREIGN KEY (new_column1) REFERENCES parent_table(new_column2);

The first line removes the existing foreign key, and the latter lines introduce a new foreign key with potentially different columns or referencing a different table.

Example: Changing a Foreign Key Reference

ALTER TABLE order_items
DROP CONSTRAINT fk_order;
ALTER TABLE order_items
ADD CONSTRAINT fk_new_order
FOREIGN KEY (new_order_id) REFERENCES new_orders(id);

In the above code, fk_order is dropped, and a new constraint, fk_new_order, is added to connect new_order_id to id in new_orders table instead.

Multiple Column Foreign Keys

PostgreSQL allows the creation of foreign keys that span multiple columns for composite keys. This is needed when the uniqueness of a record is identified by more than one column in the parent table:

ALTER TABLE child_table
ADD CONSTRAINT fk_composite
FOREIGN KEY (column1, column2) REFERENCES parent_table(ref_column1, ref_column2);

This constraint ensures that each row’s column1 and column2 combined must correspond to a row with those column values in parent_table.

Example: Adding a Composite Foreign Key

ALTER TABLE order_details
ADD CONSTRAINT fk_order_details
FOREIGN KEY (product_id, order_id) REFERENCES orders_products(product_id, order_id);

This example links two columns from order_details to orders_products, forming a composite key pairing.

Cascade Update and Delete

When creating or updating a foreign key, PostgreSQL also allows for setting rules that dictate what happens when referenced data is updated or deleted, using ON UPDATE and ON DELETE options:

ALTER TABLE child_table
ADD CONSTRAINT fk_name
FOREIGN KEY (column1) REFERENCES parent_table(column2)
ON UPDATE CASCADE
ON DELETE SET NULL;

Here, ON UPDATE CASCADE updates the child table automatically when the parent table entry is updated. The ON DELETE SET NULL sets the foreign key in the child table to NULL if the referenced data in the parent table is deleted.

Example: ON DELETE and ON UPDATE Constraints

ALTER TABLE employee
ADD CONSTRAINT fk_department
FOREIGN KEY (department_id) REFERENCES department(id)
ON UPDATE CASCADE
ON DELETE SET NULL;

This ensures that the department_id in employee table updates accordingly if the id in department changes, and becomes NULL if that department is deleted.

Checking Constraints Without Locking Tables

As of recent PostgreSQL versions, it’s possible to add a foreign key constraint without locking the table for a significant time, by using the NOT VALID option and then validating the constraint separately:

ALTER TABLE child_table
ADD CONSTRAINT fk_name FOREIGN KEY (column1) REFERENCES parent_table(column2) NOT VALID;

ALTER TABLE child_table
VALIDATE CONSTRAINT fk_name;

The first command adds the constraint but does not check existing rows. The second command can be run at a more convenient time to validate that all rows meet the constraint.

Conclusion

Adding and updating foreign key constraints in PostgreSQL is an operation that can range from straightforward to complex, depending on the specific changes required. The examples provided in this tutorial illustrate common scenarios and solutions. As always, ensure the integrity of your data by backing up your database before making structural changes, and test any alterations in a non-production environment to safeguard against unintended consequences.