A foreign key makes a business relationship enforceable by DB2 for z/OS. Instead of relying on every program to check whether a department, customer, order, or account exists, DB2 prevents dependent data from pointing to a missing parent. This hands-on tutorial shows how to inspect the data, add the constraint safely, select a delete rule, provide an appropriate index, validate the relationship, and troubleshoot common failures.
The table that owns the referenced key is the parent table. Its primary key or eligible unique key identifies one parent row. The table containing the foreign key is the dependent table, sometimes called the child table. A department can therefore be the parent of many employees: DEPARTMENT.DEPTNO is the parent key, while EMPLOYEE.DEPTNO is the foreign key in each dependent row.
The relationship is enforced in both directions. An INSERT or UPDATE of the dependent cannot introduce a non-null key with no matching parent. A DELETE of the parent must follow the relationship's delete rule. Foreign keys do not require the values in the dependent table to be unique; many employees may belong to the same department. They enforce existence, not one-to-one cardinality.
The referenced columns must already be a primary key or an eligible unique key. A nonunique index is not enough because DB2 must be able to identify one parent key unambiguously. Confirm the table schema, constraint name, key columns, and column order from the catalog rather than relying on a diagram that may be outdated.
12345678910-- Confirm the intended parent rows are unique. SELECT DEPTNO, COUNT(*) AS ROW_COUNT FROM APP.DEPARTMENT GROUP BY DEPTNO HAVING COUNT(*) > 1; -- A typical eligible parent definition: ALTER TABLE APP.DEPARTMENT ADD CONSTRAINT PK_DEPARTMENT PRIMARY KEY (DEPTNO);
If the parent key was just added, ensure its index and table space are available before continuing. Choose stable business or surrogate columns. Referencing a value that changes frequently creates avoidable update complexity because every dependent relationship must remain valid.
Each foreign-key column must be compatible with the corresponding parent-key column. Check type family, length, precision, scale, and relevant encoding attributes. For example, DECIMAL(9,0) should not casually be paired with DECIMAL(11,2), and a character identifier should use the expected length and representation. Compatible does not mean that DB2 will silently redesign the values for you.
Order is especially important for a composite key. If the parent key is (ACCOUNT_ID, REGION_CODE), the foreign key must list the dependent account identifier first and region second. Reversing them describes a different positional mapping even when both columns happen to have compatible types.
12345ALTER TABLE APP.ORDER_HEADER ADD CONSTRAINT FK_ORDER_ACCOUNT_REGION FOREIGN KEY (ACCOUNT_ID, REGION_CODE) REFERENCES APP.ACCOUNT (ACCOUNT_ID, REGION_CODE) ON DELETE RESTRICT;
A table can contain years of data before a foreign key is introduced. Find rows whose non-null dependent key has no parent before executing DDL. A NOT EXISTS anti-join states the test directly and avoids the null-related surprises that can occur with NOT IN.
12345678SELECT E.EMPNO, E.DEPTNO FROM APP.EMPLOYEE AS E WHERE E.DEPTNO IS NOT NULL AND NOT EXISTS (SELECT 1 FROM APP.DEPARTMENT AS D WHERE D.DEPTNO = E.DEPTNO) FETCH FIRST 100 ROWS ONLY;
Do not hide orphans by inserting a meaningless parent unless that row is a valid business entity. Resolve each row by creating the correct parent, correcting the dependent value, setting it to NULL when the model permits an unknown relationship, or deleting invalid data under an approved retention process. Repeat the query until it returns no rows and record the result as migration evidence.
Give the constraint a predictable, schema-wide naming convention so messages and catalog queries are understandable. The core statement names the dependent table after ALTER TABLE, the dependent columns after FOREIGN KEY, and the parent table and key after REFERENCES.
12345ALTER TABLE APP.EMPLOYEE ADD CONSTRAINT FK_EMPLOYEE_DEPARTMENT FOREIGN KEY (DEPTNO) REFERENCES APP.DEPARTMENT (DEPTNO) ON DELETE RESTRICT;
Run DDL through the site's controlled process. Confirm the authorization ID has the required privileges, account for package and statement invalidation where applicable, avoid competing utility or DDL activity, and have a backout decision prepared. The constraint immediately becomes part of the data model; it is not merely documentation.
The delete rule answers one question: what should happen when someone deletes a parent that still has dependents? It does not control deletion of a dependent row. Select the rule from business ownership and lifecycle requirements, not from convenience.
| Rule | Effect | Typical use |
|---|---|---|
| RESTRICT | Rejects deletion of a parent while matching dependents exist | Strong immediate protection when dependents must be handled explicitly first |
| NO ACTION | Requires the relationship to be valid when DB2 checks the statement | Protection similar to RESTRICT, with timing differences relevant to referential processing |
| CASCADE | Deletes matching dependent rows automatically | Owned child data whose lifetime must exactly follow the parent |
| SET NULL | Sets nullable foreign-key values to NULL instead of deleting the dependent | Dependents remain meaningful after the parent relationship is removed |
Both rules normally stop a parent delete when dependents remain, but they are not simply two spellings of the same rule. RESTRICT prevents the operation when the target parent is found to have dependents. NO ACTION requires referential integrity to be satisfied at the point DB2 performs its constraint checking, so timing and interaction with other referential actions can differ. Use the rule required by your model and test multi-table statements rather than assuming identical behavior.
CASCADE is powerful: one parent delete can remove a large dependent set and can continue through additional relationships. Use it only where children truly have no independent lifetime, and estimate logging, locking, and recovery effects. SET NULL preserves the dependent row but removes its reference. The affected foreign-key columns must support the required null result; at least one relevant foreign-key column must be nullable, and NOT NULL columns cannot be assigned NULL. Decide what a partially null composite relationship means before using it.
DB2 also restricts unsafe referential structures. Cascading cycles, conflicting delete paths, self-references, and combinations of rules may be rejected or limited. Rules vary with the exact relationship graph and Db2 level, so diagram every path from a proposed parent and check the product documentation before introducing a cascade into an existing network.
Referential integrity does not remove the need for physical design. When a parent is deleted or its key is changed, DB2 must determine whether dependent rows exist and then apply RESTRICT, NO ACTION, CASCADE, or SET NULL. Without a useful dependent-side index, that search can scan many pages, hold locks longer, and increase contention. The same index often supports joins from parent to dependent.
123456CREATE INDEX APP.IX_EMPLOYEE_DEPTNO ON APP.EMPLOYEE (DEPTNO); -- For a composite relationship, preserve the useful leading order: CREATE INDEX APP.IX_ORDER_ACCOUNT_REGION ON APP.ORDER_HEADER (ACCOUNT_ID, REGION_CODE);
Do not create a duplicate index automatically. An existing index can be suitable when the complete foreign key forms its leading columns, possibly followed by other columns. Review access paths, cardinality, clustering needs, insert cost, storage, and whether another index already provides the same prefix. The foreign-key index is normally nonunique because many dependents can reference one parent.
Existing data and object state determine the operational finish. Depending on the ALTER options, current object condition, and Db2 release, DB2 can reject invalid data or leave the affected table space requiring integrity checking. Review the SQL result and object status; a successful job step alone is not enough. If the table space is in CHECK-pending, run the site-approved CHECK DATA utility process and handle exceptions rather than simply resetting the state.
12345//CHECKFK EXEC DSNUPROC,SYSTEM=DB2A,UID='CHECKFK' //DSNUPROC.SYSIN DD * CHECK DATA TABLESPACE APPDB.EMPTS SCOPE ALL /*
Utility syntax and templates vary by installation, so tailor the sample through your DBA standards. CHECK DATA verifies referential and check constraints, and an exception table strategy can identify violating rows when required. After remediation, rerun validation, inspect utility return codes and messages, and confirm that the table space is available.
Catalog verification proves that DB2 recorded the intended relationship rather than a similarly named object. Query the relationship and column catalogs using the uppercase schema and constraint values stored by ordinary identifiers. Column sequence matters for composite keys.
12345678910111213SELECT CREATOR, RELNAME, TBNAME, REFTBCREATOR, REFTBNAME, DELETERULE FROM SYSIBM.SYSRELS WHERE CREATOR = 'APP' AND TBNAME = 'EMPLOYEE' AND RELNAME = 'FK_EMPLOYEE_DEPARTMENT'; SELECT CREATOR, TBNAME, RELNAME, COLNAME, COLSEQ FROM SYSIBM.SYSFOREIGNKEYS WHERE CREATOR = 'APP' AND TBNAME = 'EMPLOYEE' AND RELNAME = 'FK_EMPLOYEE_DEPARTMENT' ORDER BY COLSEQ;
| Source | What to verify |
|---|---|
| SYSIBM.SYSRELS | Relationship-level information such as constraint identity, parent, dependent, and rule |
| SYSIBM.SYSFOREIGNKEYS | Foreign-key column mappings and sequence for single or composite relationships |
| SYSIBM.SYSINDEXES / SYSIBM.SYSKEYS | Supporting index definitions and index-column order |
| Object status and utility output | Evidence that validation completed and no CHECK-pending state remains |
Finish with behavioral tests inside a transaction: insert a valid dependent, attempt an orphan insert and expect rejection, exercise the selected parent-delete behavior, then ROLLBACK the test changes. Use production-safe test keys and never perform destructive verification against real business rows.
A self-referencing key, such as EMPLOYEE.MANAGER_ID referencing EMPLOYEE.EMPNO, can model a hierarchy. Make the root relationship nullable or provide another valid root design, insert managers before their reports, and understand what deleting a manager should do. A cycle across tables is harder: if A requires B and B requires A, neither initial row can be inserted unless the model permits a temporary NULL or the load process establishes the data in a supported sequence.
Circular mandatory relationships often reveal that the entities should be remodeled, one relationship should be optional, or an association table should represent the connection. Cascading deletes around a cycle can be ambiguous or destructive and are subject to DB2 restrictions. Document the whole graph, not just the one ALTER TABLE statement, and test inserts, updates, deletes, LOAD processing, recovery, and utility behavior.
Always diagnose the full SQLCA, message tokens, reason code, and Db2 message text. The negative SQLCODE identifies a category, but tokens identify the actual relationship and object. Avoid repeatedly submitting the same ALTER statement after an uncertain result; query the catalog first because the constraint may already exist.
Imagine a school has a list of classrooms, and every student card says which classroom the student belongs to. The classroom list is the parent, and the student cards are the dependents. A foreign key is a careful teacher who checks that every classroom written on a card really exists. If someone removes a classroom, the delete rule tells the teacher whether to say “stop,” remove all its student cards, or erase the classroom number while keeping the cards. An index is the teacher's alphabetized card box, which makes finding all students in one classroom much faster.
1. What must exist before a DB2 foreign key can reference a parent table?
2. Why should you check for orphan rows before adding the constraint?
3. What is important when defining a composite foreign key?
4. Which delete rule automatically removes matching dependent rows?
5. Why is an index on foreign-key columns commonly recommended?