メインコンテンツにスキップ
eLearner.app
モジュール 9 · レッスン 2 / 4コース内の 34/57~12 min
モジュールのレッスン (2/4)

複数のテーブルレベルの制約

Ensuring that the data in the database is correct at the most basic layer ("data integrity") is fundamental. If you only write safety into the Node.js application, bugs could cause inconsistent data in the DB. Constraints at the DDL level are the last, impenetrable line of defense.

The main constraints

In addition to PRIMARY KEY (which makes a column unique and NOT NULL) and the classic NOT NULL and UNIQUE, there are two fundamental categories for the logical consistency of the data:

1. FOREIGN KEY (Referential Integrity)

A REFERENCES constraint ensures that a linking ID really exists in the "parent" table it points to. For example, an order must be linked to an existing customer.

SQL
CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  customer_id INTEGER REFERENCES customers(id)
);

What does the Foreign Key do?

  • It prevents you from inserting a customer_id that does not exist in customers.
  • It prevents you from DELETE (deleting) a customer from customers if there are orders pointing to them (it protects against "orphan" records).

We can also decide what should happen when the "parent" is deleted:

SQL
customer_id INTEGER REFERENCES customers(id) ON DELETE CASCADE

With ON DELETE CASCADE, if we delete the customer, Postgres will automatically remove all linked orders! (Use with great caution; normally the default setting that blocks the operation is preferable.)

2. CHECK Constraints

A CHECK constraint validates the row by testing a boolean expression before proceeding to save.

SQL
CREATE TABLE contratti (
  id SERIAL PRIMARY KEY,
  stipendio NUMERIC(10,2) CHECK (stipendio > 0),
  data_inizio DATE,
  data_fine DATE,
  CHECK (data_fine > data_inizio)
);

The first CHECK is a column constraint (it only refers to stipendio). The second CHECK at the bottom is a table constraint (it can cross values from multiple columns, and must be declared at the bottom).

If an INSERT or UPDATE tries to save the end before the start, Postgres will reject it with an error!

Naming Constraints

It is often good practice to give constraints an explicit name (using the CONSTRAINT keyword). This way, when Postgres blocks a record, the error will tell you for example "constraint 'stipendio_positivo' violated", which is much clearer for debugging!

SQL
CREATE TABLE prodotti (
  id SERIAL PRIMARY KEY,
  nome VARCHAR(50),
  CONSTRAINT nome_univoco UNIQUE(nome)
);

Try it

運動#sql.m9.l2.e1
試行回数: 0読み込み中…

Create a 'prenotazioni' table with id (SERIAL PRIMARY KEY) and a 'customer_id' (INTEGER). Use CONSTRAINT fk_cliente FOREIGN KEY (customer_id) REFERENCES customers(id) to give an explicit name to the Foreign Key constraint. Do it at the bottom, as a table constraint.

エディターを読み込み中…
ヒントを表示

Write CONSTRAINT fk_cliente FOREIGN KEY (local_column) REFERENCES external_table(external_col)

3 回の試行後に解決策が利用可能になります

Constraints with custom logic

運動#sql.m9.l2.e2
試行回数: 0読み込み中…

Create an 'eventi' table with id (SERIAL PRIMARY KEY), posti_totali (INTEGER) and biglietti_venduti (INTEGER). Add a table constraint named 'check_capienza' where biglietti_venduti must never be greater than posti_totali.

エディターを読み込み中…
ヒントを表示

Add the constraint at the bottom using CONSTRAINT check_capienza CHECK ( expression )

3 回の試行後に解決策が利用可能になります