Skip to content
Back to skills

Foreign Key Constraints

ASecurity

Foreign Key Constraints

  • 17 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 2, 2026
ai-agentsgosqlazuredatabase

Security analysis

A100/100

Scanned September 2, 2026

npx -y skills add CarlosCaPe/octorato --skill foreign-key-constraints --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Foreign Key Constraints?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Foreign Key Constraints
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/carloscape-foreign-key-constraints/badge)](https://www.skillsdirectory.com/skills/carloscape-foreign-key-constraints)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: foreign-key-constraints
description: "Foreign Key Constraints"
metadata:
  short-description: "Foreign Key Constraints"
  original-index: 09
---

# Foreign Key Constraints

## What

`ALTER TABLE ADD CONSTRAINT ... FOREIGN KEY` enforces referential integrity
between tables. The FK guarantees that every value in the child column exists
in the parent table's referenced column.

## Why

Without FKs, orphaned records accumulate silently. A `HospitalId` in an
appointments table might reference a hospital that no longer exists. FKs
catch this at INSERT/UPDATE time, preventing data corruption.

## How

### Standard FK pattern (NOT VALID + VALIDATE)
```sql
-- Step 1: Add the constraint without scanning existing rows (instant)
ALTER TABLE public."AppointmentInfo"
    ADD CONSTRAINT fk_appointmentinfo_hospitalid
    FOREIGN KEY ("HospitalId")
    REFERENCES public."Hospital"("HospitalId")
    NOT VALID;

-- Step 2: Validate existing rows (non-blocking, allows concurrent reads)
ALTER TABLE public."AppointmentInfo"
    VALIDATE CONSTRAINT fk_appointmentinfo_hospitalid;
```

Why NOT VALID + VALIDATE?
- `ADD FOREIGN KEY` acquires `SHARE ROW EXCLUSIVE` lock on both the
  child table AND the referenced (parent) table -- lighter than the
  `ACCESS EXCLUSIVE` used by most ALTER TABLE forms
  (PG 16 docs: sql-altertable.html)
- `NOT VALID` skips scanning existing rows -- constraint creation is fast
- New inserts/updates ARE validated immediately against the FK
- `VALIDATE CONSTRAINT` scans existing rows with an even weaker lock
  (`SHARE UPDATE EXCLUSIVE`) that allows concurrent reads AND writes;
  it also acquires only `ROW SHARE` on the referenced table
  (PG 16 docs: sql-altertable.html)
- This is the recommended pattern in our
  [Best Practices](../DOCUMENTS/PostgreSQL_BestPractices_Azure.md)

### FK with explicit actions
```sql
ALTER TABLE public."ChildTable"
    ADD CONSTRAINT fk_child_parent
    FOREIGN KEY ("ParentId")
    REFERENCES public."ParentTable"("Id")
    ON DELETE CASCADE
    ON UPDATE CASCADE
    NOT VALID;

ALTER TABLE public."ChildTable"
    VALIDATE CONSTRAINT fk_child_parent;
```

### Idempotent pattern
```sql
DO $$
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM information_schema.table_constraints
        WHERE constraint_name = 'fk_appointmentinfo_hospitalid'
          AND table_schema = 'public'
    ) THEN
        ALTER TABLE public."AppointmentInfo"
            ADD CONSTRAINT fk_appointmentinfo_hospitalid
            FOREIGN KEY ("HospitalId")
            REFERENCES public."Hospital"("HospitalId");
        RAISE NOTICE 'Created FK: fk_appointmentinfo_hospitalid';
    ELSE
        RAISE NOTICE 'Skipped: fk_appointmentinfo_hospitalid (already exists)';
    END IF;
END $$;
```

## Pre-Requisites

Before adding a FK, verify:
1. **No orphans exist** -- see **Skill #24** (Orphan Detection & FK Rollout)
   for the full scan + remediation workflow
2. **Parent column has a unique index** (usually PK or UNIQUE constraint)
3. **Data types match** between child and parent columns

## When to Use

- Any column that references another table's primary key
- After database audits identify missing referential integrity
- As part of schema hardening / best practices enforcement

## Where We Used It

- ****: FK on `AppointmentInfo.HospitalId` -> `Hospital.HospitalId`
- ****: FK on `AppointmentInfo.ProviderId` -> `Provider.ProviderId`

## Related Skills

- **Skill #24** (Orphan Detection & FK Rollout) -- orphan scan + data cleanup
  before FK creation
- **Skill #10** (Index CONCURRENTLY) -- supporting indexes for FK columns
- **Skill #20** (Procedure Hardening) -- FK-aware delete ordering in procedures

## References

- [PostgreSQL Best Practices](../DOCUMENTS/PostgreSQL_BestPractices_Azure.md)
  -- see "Foreign keys and constraints" in Design & Modeling

## Gotchas

- Always use `NOT VALID` + `VALIDATE CONSTRAINT` (see main example above)
- `ADD FOREIGN KEY` locks BOTH the child AND the parent table with
  `SHARE ROW EXCLUSIVE` -- coordinate with teams owning the parent table
- FKs create implicit dependencies -- `DROP TABLE parent` will fail
- FKs can slow down INSERT/UPDATE/DELETE on the child table (each operation
  checks the parent)
- Always create a supporting index on the FK column (Skill #10) --
  PostgreSQL does NOT auto-create indexes on FK columns
- On partitioned tables, FKs cannot be declared `NOT VALID`
  (PG 16 limitation -- see Skill #34)

---

*Category: DDL | Origin: , *

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.