
This is another one of those posts I did not realize I had not written about, database constraints.
Constraints allow me to move the control the integrity of my data into the database itself. I am going to give some simple examples of what can be achieved with constraints with DDL Tables. Here I am going to cover the following:
There are other types of constraints, but for this post I am only going to write about these.
Unique constraint
A unique constraint ensures that the rows in a Table are unique. Which is what we want, as we do not want to have Tables containing duplicate Employee ids, or Customer numbers.
This is my example of a Table created with a unique constraint:
01 CREATE TABLE MYLIB.PARENT1 ( 02 PARENT_ID INTEGER NOT NULL, 03 LAST_NAME VARCHAR(30) NOT NULL, 04 FIRST_NAME VARCHAR(20) NOT NULL, 05 DATE_OF_BIRTH DATE NOT NULL, 06 UNIQUE (PARENT_ID)) |
Line 6: The UNIQUE keyword ensures that my Table will not allow duplicate PARENT_ID values.
I can use the TABLE_CONSTRAINTS View to check the type of constraint I have for this Table:
01 SELECT TABLE_NAME, 02 CONSTRAINT_NAME, 03 CONSTRAINT_TYPE 04 FROM SYSIBM.TABLE_CONSTRAINTS 05 WHERE TABLE_SCHEMA = 'MYLIB' 06 AND TABLE_NAME = 'PARENT1' |
Lines 1 – 3: I am only interested in three columns:
- TABLE_NAME: Name of the Table
- CONSTRAINT_NAME: Name of the constraint
- CONSTRAINT_TYPE: Type of constraint
The result for this statement is:
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE ---------- --------------------------------- --------------- PARENT1 Q_MYLIB_PARENT1_PARENT_ID_00001 UNIQUE |
The name of the constraint is automatically, and the constraint type columns informs us that it is unique.
I can get more information from the SYSFILES View:
01 SELECT SYSTEM_TABLE_NAME, 02 CONSTRAINT_COUNT, 03 NUMBER_KEY_FIELDS, 04 PRIMARY_KEY, 05 UNIQUE_CONSTRAINT, 06 ACCESS_PATH_TYPE 07 FROM QSYS2.SYSFILES 08 WHERE SYSTEM_TABLE_SCHEMA = 'MYLIB' 09 AND TABLE_NAME = 'PARENT1' |
This statement returns the following result:
SYSTEM_ NUMBER TABLE_ CONSTRAINT _KEY_ PRIMARY UNIQUE_ ACCESS_ NAME _COUNT FIELDS _KEY CONSTRAINT PATH_TYPE ------- ---------- ------ ------- ---------- ------------ PARENT1 1 0 NO NO <NULL> |
This show that the PERSON1 Table has a constraint, but no key.
What happens when I insert data into the Table?
01 INSERT INTO PARENT1 VALUES(1,'SMITH','JOHN','1995-09-30') |
This statement is successful as there is no row in the Table with the PERSON_ID or '1'.
02 INSERT INTO PARENT1 VALUES(1,'SMITH','JANE','1997-08-09') |
This statement errors as there is already a row in the Table with the PERSON_ID of '1'.
SQL State: 23505 Vendor Code: -803 Message: [SQL0803] Duplicate key value specified. Cause . . . . . : A unique index or unique constraint *N in *N exists over one or more columns of table PARENT1 in MYLIB. The operation cannot be performed because one or more values would have produced a duplicate key in the unique index or constraint. |
Primary key constraint
The primary key constraint performs two purposes. Firstly, it defines the primary key for the Table. Secondly, it provides the unique constraint too.
My example Table with the primary key is:
01 CREATE TABLE MYLIB.PARENT2 ( 02 PARENT_ID INT NOT NULL, 03 LAST_NAME VARCHAR(30) NOT NULL, 04 FIRST_NAME VARCHAR(20) NOT NULL, 05 DATE_OF_BIRTH DATE NOT NULL, 06 PRIMARY KEY (PARENT_ID)) |
Line 6: This is where I have defined the primary key as being the PARENT_ID.
As I did with PARENT1 I can check the constraint using TABLE_CONSTRAINT:
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE ---------- --------------------------------- --------------- PARENT2 Q_MYLIB_PARENT2_PARENT_ID_00001 PRIMARY KEY |
The CONSTRAINT_TYPE shows that the Table has a primary key.
Checking SYSFILES:
01 SELECT SYSTEM_TABLE_NAME, 02 CONSTRAINT_COUNT, 03 NUMBER_KEY_FIELDS, 04 PRIMARY_KEY, 05 UNIQUE_CONSTRAINT, 06 ACCESS_PATH_TYPE 07 FROM QSYS2.SYSFILES 08 WHERE SYSTEM_TABLE_SCHEMA = 'MYLIB' 09 AND TABLE_NAME = 'PARENT2' |
Gives me the following result:
SYSTEM_ NUMBER TABLE_ CONSTRAINT _KEY_ PRIMARY UNIQUE_ ACCESS_ NAME _COUNT FIELDS _KEY CONSTRAINT PATH_TYPE ------- ---------- ------ ------- ---------- ------------ PARENT2 1 1 YES NO KEYED UNIQUE |
I can see I have one key field, and the Table has a unique key.
When attempting to insert the same two values in PERSON2, that I did for PERSON1,.../p>
01 INSERT INTO PARENT2 VALUES(1,'SMITH','JOHN','1995-09-30') ; 02 INSERT INTO PARENT2 VALUES(1,'SMITH','JANE','1997-08-09') ; |
I get the same error for the second insert statement as the key is the same as the previously inserted row.
SQL State: 23505 Vendor Code: -803 Message: [SQL0803] Duplicate key value specified. Cause . . . . . : A unique index or unique constraint *N in *N exists over one or more columns of table PARENT1 in MYLIB. The operation cannot be performed because one or more values would have produced a duplicate key in the unique index or constraint. |
Foreign key constraint
The foreign key constraint ensures that the foreign key column that is being inserted or updated in the child Table must exist in the parent Table.
I decided to call my child table CHILD, and it looks like:
01 CREATE TABLE MYLIB.CHILD ( 02 PARENT_ID INT NOT NULL, 03 CHILD_ID INT NOT NULL, 04 LAST_NAME VARCHAR(30) NOT NULL, 05 FIRST_NAME VARCHAR(20) NOT NULL, 06 DATE_OF_BIRTH DATE NOT NULL, 07 PRIMARY KEY (PARENT_ID,CHILD_ID), 08 CONSTRAINT PARENT_ID_EXISTS 09 FOREIGN KEY(PARENT_ID) 10 REFERENCES PARENT2 11 ON DELETE RESTRICT) |
Line 2: PARENT_ID is the foreign key.
Line 7: I define a primary key constraint to provide the Table with an appropriate access path, and to ensure that there is a unique constraint too.
Lines 8 – 10: This is the definition that enforces the definition of the foreign key. On line 8 I give this constraint a name, PARENT_ID_EXISTS. I use the FOREIGN KEY on line 9 to give the column name of what will be used as the foreign key. And on line 10 I state within which Table the foreign key is found.
Line 11: This line restricts any delete. Which means I cannot delete a row from the parent file if there are matching rows in the child.
When I use TABLE_CONSTRAINTS to list the constraints on this file...
01 SELECT TABLE_NAME, 02 CONSTRAINT_NAME, 03 CONSTRAINT_TYPE 04 FROM SYSIBM.TABLE_CONSTRAINTS 05 WHERE TABLE_SCHEMA = 'MYLIB' 06 AND TABLE_NAME = 'CHILD' |
I have two results.
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE ---------- --------------------------------- --------------- CHILD Q_MYLIB_CHILD_PARENT_ID_00001 PRIMARY KEY CHILD PARENT_ID_EXISTS FOREIGN KEY |
The first result is for the primary key. And the second for the foreign key.
When I check this file using SYSFILES I see...
01 SELECT SYSTEM_TABLE_NAME, 02 CONSTRAINT_COUNT, 03 NUMBER_KEY_FIELDS, 04 PRIMARY_KEY, 05 UNIQUE_CONSTRAINT, 06 ACCESS_PATH_TYPE 07 FROM QSYS2.SYSFILES 08 WHERE SYSTEM_TABLE_SCHEMA = 'MYLIB' 09 AND TABLE_NAME LIKE 'CHILD' |
This returns:
SYSTEM_ NUMBER TABLE_ CONSTRAINT _KEY_ PRIMARY UNIQUE_ ACCESS_ NAME _COUNT FIELDS _KEY CONSTRAINT PATH_TYPE ------- ---------- ------ ------- ---------- ------------ CHILD 2 2 YES NO KEYED UNIQUE |
A result that tells me I have two constraints on this file.
I insert a row of data into CHILD that has the same PARENT_ID as the row in PARENT2.
INSERT INTO CHILD VALUES(1,1,'SMITH','JANE','1997-08-09') |
Now I can show referential integrity in action. When I try to delete this row from the parent file:
DELETE FROM PARENT2 WHERE PARENT_ID = 1 |
As I have the ON DELETE RESTRICT in the child Table it will not allow the delete. Instead, I receive the following error explaining why it cannot.
SQL State: 23001 Vendor Code: -532 Message: [SQL0532] Delete prevented by referential constraint PARENT_ID_EXISTS in MYLIB. Cause . . . . . : Constraint PARENT_ID_EXISTS in MYLIB identifies the table being modified as the parent table in a relationship with dependent table CHILD in MYLIB, with a delete rule of RESTRICT or NO ACTION. The deletion of a row is prevented when there are rows in the dependent table with matching values. |
And if I try to insert a row into the child that does not have a matching row in the parent:
INSERT INTO CHILD VALUES(2,1,'JONES','TAMMY','1990-03-16') |
I get a different message, as there is not a matching row in the PERSON2 Table.
SQL State: 23503 Vendor Code: -530 Message: [SQL0530] Operation not allowed by referential constraint PARENT_ID_EXISTS in MYLIB. Cause . . . . . : If this is an INSERT, UPDATE, or MERGE statement, the value is not valid for the foreign key because it does not have a matching value in the parent key. |
These examples show how easy it is to "push" validation from our programs into the database. This is preferred as the same rules are applied however I manipulate the data in either the parent or child, thereby, ensuring the database will not contain duplicate key rows or orphan children rows.
You can learn more about the constraints from the IBM website here.
This article was written for IBM i 7.6, and should work for some earlier releases too.
No comments:
Post a Comment
To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.
Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.