A DB2 for z/OS primary key gives a table one official, stable way to identify each row. Adding that key to an existing table is more than typing an ALTER statement: the current data must already satisfy the rule, every key column must reject nulls, and DB2 needs a unique index that can enforce the key. This hands-on tutorial covers inspection, cleanup decisions, SQL syntax, composite key order, catalog verification, utility effects, common failures, and a safe production sequence.
A primary key implements entity integrity. In plain language, every row represents one identifiable thing, and that identity is never missing or repeated. For an employee table, EMPNO might identify one employee. For an order-line table, neither ORDER_ID nor LINE_NO is sufficient by itself, but the pair identifies one line within one order. DB2 records this business rule as a table constraint and enforces it whenever data is inserted, updated, or loaded with constraint enforcement.
Primary key, UNIQUE constraint, and unique index are related but not identical. The primary key is the table's chosen identity and can be referenced by foreign keys. A UNIQUE constraint describes another candidate key. A unique index is the physical access structure DB2 uses to prevent duplicate values. One table may have several unique indexes and UNIQUE constraints, but it can have only one primary key.
| Requirement | Why it matters |
|---|---|
| No nulls | Every primary-key component must be known because the key is the row identity |
| No duplicate combinations | The complete key value must identify at most one row |
| NOT NULL definition | Clean data alone is not enough; the catalog definition must prohibit future nulls |
| One primary key | A table has one official primary key, although it can have other candidate keys |
| Unique index enforcement | DB2 uses a unique primary index to enforce uniqueness efficiently |
Never assume that a column named ID is safe. Older applications may have permitted nulls, reused default values, or generated identifiers only for newer rows. First count rows whose candidate key is incomplete. For a single-column key, test that column. For a composite key, test every component because one null makes the proposed identity incomplete.
12345678910-- Candidate key: APP.CUSTOMER(CUSTOMER_ID) SELECT COUNT(*) AS NULL_KEY_ROWS FROM APP.CUSTOMER WHERE CUSTOMER_ID IS NULL; -- Candidate composite key: APP.ORDER_LINE(ORDER_ID, LINE_NO) SELECT COUNT(*) AS NULL_KEY_ROWS FROM APP.ORDER_LINE WHERE ORDER_ID IS NULL OR LINE_NO IS NULL;
Next find duplicates. Group by the complete candidate key, count each group, and retain only counts greater than one. Do not check composite columns independently. Many order lines can correctly share ORDER_ID, and many orders can correctly contain LINE_NO 1; only the combination must be unique.
12345678910111213-- Single-column duplicate inspection SELECT CUSTOMER_ID, COUNT(*) AS ROW_COUNT FROM APP.CUSTOMER GROUP BY CUSTOMER_ID HAVING COUNT(*) > 1 ORDER BY ROW_COUNT DESC; -- Composite-key duplicate inspection SELECT ORDER_ID, LINE_NO, COUNT(*) AS ROW_COUNT FROM APP.ORDER_LINE GROUP BY ORDER_ID, LINE_NO HAVING COUNT(*) > 1 ORDER BY ROW_COUNT DESC;
Treat every result as a business-data issue, not merely a DDL obstacle. A duplicate might represent accidental double loading, two legitimate entities that need a better key, or a historical row that should be retained with a version number. Decide whether to merge, delete, renumber, archive, or redesign with the data owner. Keep evidence of row counts before and after remediation, and rerun both null and duplicate checks immediately before deployment.
Having no null values today does not make a nullable column eligible forever. Its catalog definition must prevent future nulls. After confirming the data and application impact, alter each proposed key column to NOT NULL using syntax supported by your DB2 level and local change process. Existing INSERT statements that omit the column, host programs that supply a negative null indicator, and LOAD jobs that contain null fields must be corrected before enforcement begins.
12345678ALTER TABLE APP.CUSTOMER ALTER COLUMN CUSTOMER_ID SET NOT NULL; ALTER TABLE APP.ORDER_LINE ALTER COLUMN ORDER_ID SET NOT NULL; ALTER TABLE APP.ORDER_LINE ALTER COLUMN LINE_NO SET NOT NULL;
Depending on the existing definition, table-space organization, DB2 level, and exact ALTER operation, DB2 can require validation or follow-up utility work. Test the same DDL against a production-like copy and record any object status change. Do not proceed to the constraint merely because the ALTER statement returned successfully; verify that the catalog now shows each key column as not nullable.
The standard form names the constraint and lists the key columns. A meaningful constraint name makes messages, catalog queries, and future changes easier to understand. Naming conventions vary, but names such as PK_CUSTOMER and PK_ORDER_LINE clearly communicate the purpose.
1234567ALTER TABLE APP.CUSTOMER ADD CONSTRAINT PK_CUSTOMER PRIMARY KEY (CUSTOMER_ID); ALTER TABLE APP.ORDER_LINE ADD CONSTRAINT PK_ORDER_LINE PRIMARY KEY (ORDER_ID, LINE_NO);
DB2 validates the definition and establishes unique index enforcement. If the data or column definitions violate the rule, the operation fails or requires corrective handling according to the reported condition. Do not respond by disabling checks or deleting rows blindly. Read the SQLCODE and messages, identify the exact key or object state, correct the underlying cause, and repeat the prechecks.
In PRIMARY KEY (ORDER_ID, LINE_NO), the sequence is ORDER_ID first and LINE_NO second. Reversing the sequence still tests uniqueness across the same pair, but it creates a different ordered index and a different key sequence in the catalog. ORDER_ID first is normally useful when applications retrieve all lines for one order, because matching the leading index column supports that access path. LINE_NO first would organize entries primarily by line number across orders and might not support that common query as well.
Choose order from the entity relationship and important access paths, not alphabetical preference. Also remember that foreign keys referencing the primary key normally use the corresponding parent-column sequence. Changing primary-key order later is a coordinated schema change involving indexes, dependent constraints, applications, packages, and utilities, so make the decision deliberately.
DB2 enforces the primary key through a unique index. When no suitable index exists, DB2 can create the required unique primary index as part of establishing the constraint. That automatic behavior is convenient, but the generated index might not use the naming, buffer pool, storage, partitioning, or clustering choices your database standards prefer. Always inspect the resulting catalog entries.
A suitable existing unique index may be designated to enforce the primary key. Before relying on one, compare its table, key columns, column order, uniqueness, expressions, and other relevant attributes with the planned constraint. An index on (ORDER_ID, LINE_NO) is not interchangeable with one on (LINE_NO, ORDER_ID) for ordered access, even though both can make the pair unique. An index that includes extra key columns does not prove that the shorter primary-key combination is unique.
Some teams deliberately create the exact unique index first so they control its physical design and discover duplicates during the index build before the constraint change. This can be valuable, but it does not replace the constraint: applications and catalog tools should see the declared entity rule, not infer it from an index. Confirm in a test environment whether DB2 selects the intended index and how it marks that index after the primary key is added.
A successful completion code is only the first check. Query SYSTABCONST to confirm the table constraint, SYSKEYCOLUSE to confirm every key column and its sequence, and SYSINDEXES to identify the unique primary index. Catalog column availability can vary by DB2 release, so adapt selected diagnostic columns to your supported catalog level.
123456789101112131415161718SELECT CREATOR, NAME, CONSTNAME, TYPE FROM SYSIBM.SYSTABCONST WHERE CREATOR = 'APP' AND NAME = 'ORDER_LINE' AND TYPE = 'P'; SELECT TBCREATOR, TBNAME, CONSTNAME, COLNAME, COLSEQ FROM SYSIBM.SYSKEYCOLUSE WHERE TBCREATOR = 'APP' AND TBNAME = 'ORDER_LINE' AND CONSTNAME = 'PK_ORDER_LINE' ORDER BY COLSEQ; SELECT CREATOR, NAME, TBCREATOR, TBNAME, UNIQUERULE, CLUSTERING FROM SYSIBM.SYSINDEXES WHERE TBCREATOR = 'APP' AND TBNAME = 'ORDER_LINE' ORDER BY CREATOR, NAME;
For the enforcing primary index, review the unique-rule designation, key metadata, and operational attributes rather than choosing the first index returned. Then run negative tests in a controlled environment: attempt a duplicate key and a null key, confirm that DB2 rejects them, roll back the test unit of work, and run a valid insert or update. Finally, test child-table foreign keys and representative application transactions.
Adding a primary key to a populated table can be expensive because DB2 must establish that all existing rows satisfy uniqueness and build or designate an index. A large index build consumes CPU, elapsed time, sort space, I/O, and log or utility resources. DDL and utility serialization can also conflict with applications, LOAD, REORG, COPY, or other activity. Estimate the work from production-like volume instead of extrapolating from an empty test table.
Review every LOAD process. Future input must provide non-null key values and must not duplicate existing or incoming rows. Utility options determine when constraints and indexes are enforced, what rows are discarded, and whether an object enters a restrictive state that requires CHECK DATA, REBUILD INDEX, REORG, or another documented action. Do not assume that an old LOAD card remains safe after the new constraint.
| Symptom | Likely cause | Safe response |
|---|---|---|
| ALTER reports nullability or invalid key columns | One or more proposed columns are still nullable in the catalog | Clean the data and alter every key column to NOT NULL before retrying |
| Unique index creation finds duplicate keys | The candidate is not unique, or the duplicate query used the wrong column set | Resolve each duplicate according to business rules and repeat the full-key check |
| A primary key already exists | The table already has a type P constraint | Inspect SYSTABCONST; use UNIQUE for another candidate key or redesign deliberately |
| Unexpected index was created | No existing unique index matched the required key design | Review SYSINDEXES and use a planned index strategy in the tested deployment |
| Utility or application work is delayed | Validation, index build, locks, or object states conflict with active workload | Follow the outage and utility plan, inspect object status, and reschedule safely |
Exact SQLCODEs depend on the failed operation and object state. Capture the complete SQLCA, DSNTIAR text, and utility messages instead of reducing an incident to a generic "ALTER failed." The constraint name, conflicting key, index name, and reason code usually point to the correct remediation. If production data ownership is unclear, stop and involve the application owner rather than making irreversible cleanup guesses.
A backout plan must reflect reality. After new application data relies on the constraint or child tables reference it, simply dropping the primary key may be unsafe or blocked by dependencies. Prefer a rehearsed forward-fix where possible, and document the point after which recovery requires coordinated application and database action.
Imagine a classroom where every child receives one badge number. No badge can be blank, and two children cannot have the same number. The teacher's rule saying "badge number identifies the child" is the primary key. The sorted badge list the teacher checks quickly is the unique index. For children on teams, the badge might use both team number and child number; that is a composite key. Before making the rule official, the teacher checks that nobody has a blank or copied badge.
1. What must be true of every column in a DB2 primary key?
2. What should you inspect before adding a composite primary key?
3. How many primary keys can one DB2 table have?
4. Why might a team create an appropriate unique index before adding the constraint?
5. Which catalog tables are useful for verifying a primary key and its column order?