• Aucun résultat trouvé

Frequency of Foreign Key Checking

Dans le document IntroductionandConcepts PostgreSQL (Page 192-197)

By default, foreign key constraints are checked at the end of each INSERT,UPDATE, andDELETE

query. Thus, if you perform a set of complex table modifications, the foreign key constraints must remain valid at all times. For example, using the tables in Figure14.7, if a new state is added and then a new customer in the new state is inserted, the new state must be added to statename before the customer is added to customer.

In some cases, it may not be possible to keep foreign key constraints valid between queries. For example, if two tables are foreign keys for each other, it may not be possible toINSERTinto one table without having the other table row already present. A solution is to use theDEFERRABLEforeign key option and SET CONSTRAINTSso that foreign key constraints are checked only at transaction commit. With this approach, a multiquery transaction can make table modifications that violate foreign key constraints inside the transaction as long as the foreign key constraints are met at

14.4. FOREIGN KEY/REFERENCES 165

test=> INSERT INTO primarytest2 test-> VALUES (1,2);

INSERT 148816 1

test=> INSERT INTO foreigntest2 test-> VALUES (1,2);

INSERT 148817 1

test=> UPDATE foreigntest2 test-> SET col4 = NULL;

UPDATE 1

test=> CREATE TABLE matchtest (

test(> col3 INTEGER,

test(> col4 INTEGER,

test(> FOREIGN KEY (col3, col4) REFERENCES primarytest2

test(> MATCH FULL

test(> );

NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s) CREATE

test=> UPDATE matchtest

test-> SET col3 = NULL, col4 = NULL;

UPDATE 1

test=> UPDATE matchtest test-> SET col4 = NULL;

ERROR: <unnamed> referential integrity violation

-MATCH FULL doesn’t allow mixing of NULL and NON-NULL key values Figure 14.13:MATCH FULLforeign key

166 CHAPTER 14. CONSTRAINTS transactions commit. Figure14.14is a contrived example of this case; the proper way to perform this query is toINSERTinto primarytest first, thenINSERTinto defertest. In complex situations, such reordering might not be possible, so DEFERRABLEandSET CONSTRAINTSshould be used to defer foreign key constraints. A foreign key may also be configured asINITIALLY DEFERRED,causing the constraint to be checked only at transaction commit by default.

You can name constraints if desired. The constraint names will appear in constraint violation messages and can be used bySET CONSTRAINTS.See theCREATE_TABLEandSETmanual pages for more information.

14.5 C

HECK

TheCHECKconstraint enforces column value restrictions. Such constraints can restrict a column, for example, to a set of values, only positive numbers, or reasonable dates. Figure14.15shows an example ofCHECKconstraints using a modified version of the friend table from Figure3.2, page13.

This figure has manyCHECKclauses:

state Forces the column to be two characters long. CHAR()pads the field with spaces, so state must be trim()-ed of trailing spaces before length() is computed.

age Forces the column to hold only positive values.

gender Forces the column to hold either M or F.

last_met Forces the column to include dates between January 1, 1950, and the current date.

table Forces the table to accept only rows where firstname is not ED or lastname is not RIVERS.

The effect is to prevent Ed Rivers from being entered into the table. His name will be rejected if it is in uppercase, lowercase, or mixed case. This restriction must be implemented as a table-levelCHECKconstraint. Comparing firstname to ED at the column level would have prevented all EDs from being entered, which was not desired. Instead, the desired restriction is a combination of firstname and lastname.

Next, the example tries toINSERTa row that violates allCHECKconstraints. Although theCHECK

failed on the friend2_last_met constraint, if that were corrected, the other constraints would prevent the insertion. By default,CHECKallowsNULLvalues.

14.6 Summary

This chapter covered a variety of constraints that help restrict user data within specified limits.

With small databases, constraints are of marginal benefit. With databases holding millions of rows, however, they help keep database information organized and complete.

14.6. SUMMARY 167

test=> CREATE TABLE defertest(

test(> col2 INTEGER REFERENCES primarytest

test(> DEFERRABLE

test(> );

NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s) CREATE

test=> BEGIN;

BEGIN

test=> -- INSERT is attempted in non-DEFERRABLE mode test=>

test=> INSERT INTO defertest VALUES (5);

ERROR: <unnamed> referential integrity violation -key referenced from defertest not found in primarytest test=> COMMIT;

COMMIT test=> BEGIN;

BEGIN

test=> -- all foreign key constraints are set to DEFERRED test=>

test=> SET CONSTRAINTS ALL DEFERRED;

SET CONSTRAINTS

test=> INSERT INTO defertest VALUES (5);

INSERT 148946 1

test=> INSERT INTO primarytest VALUES (5);

INSERT 148947 1 test=> COMMIT;

COMMIT

Figure 14.14:DEFERRABLEforeign key constraint

test=> CREATE TABLE friend2 (

test(> firstname CHAR(15), test(> lastname CHAR(20),

test(> city CHAR(15),

test(> state CHAR(2) CHECK (length(trim(state)) = 2), test(> age INTEGER CHECK (age >= 0),

test(> gender CHAR(1) CHECK (gender IN (’M’,’F’)),

test(> last_met DATE CHECK (last_met BETWEEN ’1950-01-01’

test(> AND CURRENT_DATE),

test(> CHECK (upper(trim(firstname)) != ’ED’ OR test(> upper(trim(lastname)) != ’RIVERS’) test(> );

CREATE

test=> INSERT INTO friend2

test-> VALUES (’Ed’, ’Rivers’, ’Wibbleville’, ’J’, -35, ’S’, ’1931-09-23’);

ERROR: ExecAppend: rejected due to CHECK constraint friend2_last_met Figure 14.15: CHECKconstraints

Chapter 15

Dans le document IntroductionandConcepts PostgreSQL (Page 192-197)