Skip to content

Cum să folosești chei străine în SQL — ON DELETE CASCADE, RESTRICT

DodaTech Updated 2025-01-15 3 min read

In this tutorial, you'll learn about Cum să folosești chei străine în SQL. We cover key concepts, practical examples, and best practices.

Cum să folosești chei străine (FOREIGN KEY) în SQL pentru a menține integritatea referențială între tabele, cu opțiunile ON DELETE CASCADE, RESTRICT, SET NULL și ON UPDATE.

Problema

Într-o bază de date relațională, tabelele sunt legate între ele prin chei. Dacă ștergi un rând părinte (ex: un client), rândurile copil (ex: comenzile clientului) rămân orfane — fac referire la un ID care nu mai există. Aceste date orfane duc la erori și inconsistență.

The Wrong Way

Omisiunea cheilor străine sau definirea lor fără acțiuni de ștergere:

CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT,
    total DECIMAL(10,2)
);
-- FĂRĂ FOREIGN KEY constraint
-- Acum poți șterge clienți, iar comenzile rămân orfane
DELETE FROM customers WHERE id = 1;
-- Comenzile cu customer_id = 1 există în continuare
-- Orice JOIN viitor va returna NULL sau date greșite

The Right Way

Definește chei străine cu acțiuni explicite:

CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT NOT NULL,
    total DECIMAL(10,2),
    CONSTRAINT fk_orders_customer
        FOREIGN KEY (customer_id)
        REFERENCES customers(id)
        ON DELETE CASCADE
        ON UPDATE CASCADE
);

ON DELETE CASCADE

Șterge automat rândurile copil când părintele este șters:

DELETE FROM customers WHERE id = 1;
-- Automat: toate comenzile clientului 1 sunt șterse
-- Verifică:
SELECT * FROM orders WHERE customer_id = 1;  -- 0 rânduri

ON DELETE RESTRICT

Previne ștergerea părintelui dacă există copii:

ALTER TABLE orders
ADD CONSTRAINT fk_orders_customer
FOREIGN KEY (customer_id)
REFERENCES customers(id)
ON DELETE RESTRICT;

DELETE FROM customers WHERE id = 1;
-- EROARE: update or delete on table "customers" violates foreign key
-- constraint "fk_orders_customer" on table "orders"

ON DELETE SET NULL

Setează cheia străină la NULL când părintele este șters:

ALTER TABLE orders
ADD CONSTRAINT fk_orders_customer
FOREIGN KEY (customer_id)
REFERENCES customers(id)
ON DELETE SET NULL;

DELETE FROM customers WHERE id = 1;
-- customer_id în orders devine NULL pentru comenzile clientului 1

Step-by-Step Fix

1. Adaugă cheie străină la crearea tabelei

CREATE TABLE order_items (
    id INT PRIMARY KEY,
    order_id INT NOT NULL
        REFERENCES orders(id) ON DELETE CASCADE,
    product_id INT NOT NULL
        REFERENCES products(id) ON DELETE RESTRICT
);

2. Adaugă cheie străină pe un tabel existent

ALTER TABLE order_items
ADD CONSTRAINT fk_items_product
FOREIGN KEY (product_id)
REFERENCES products(id)
ON DELETE RESTRICT;

3. Verifică integritatea

-- Găsește rânduri orfane (fără părinte)
SELECT o.*
FROM orders o
LEFT JOIN customers c ON o.customer_id = c.id
WHERE c.id IS NULL;

Prevention Tips

  • Folosește ON DELETE CASCADE pentru relații de tip părinte-copil unde copilul nu are sens fără părinte
  • Folosește ON DELETE RESTRICT pentru referințe critice unde nu vrei ștergeri accidentale
  • Folosește ON DELETE SET NULL pentru relații opționale
  • Nu uita să adaugi indecși pe coloanele cheii străine

Greșeli comune cu chei străine

  1. Fără chei străine deloc — date orfane și inconsistență
  2. CASCADE pe lanțuri lungi — șterge în cascadă prea multe date
  3. Lipsa indexului pe cheia străină — JOIN-urile devin foarte lente
  4. Confuzia între RESTRICT și NO ACTION — sunt aproape identice
  5. Chei străine ciclice — două tabele care se referă reciproc, imposibil de inserat

Exercițiu practic

Creează 3 tabele: authors (id, name), books (id, title, author_id), reviews (id, book_id, rating). Folosește CASCADE pentru authors→books, și RESTRICT pentru books→reviews. Testează ștergerea unui autor.

Soluție:

CREATE TABLE authors (
    id INT PRIMARY KEY,
    name VARCHAR(100)
);
CREATE TABLE books (
    id INT PRIMARY KEY,
    title VARCHAR(200),
    author_id INT REFERENCES authors(id) ON DELETE CASCADE
);
CREATE TABLE reviews (
    id INT PRIMARY KEY,
    book_id INT REFERENCES books(id) ON DELETE RESTRICT,
    rating INT
);

FAQ

### Care este diferența dintre RESTRICT și NO ACTION?

În PostgreSQL, RESTRICT și NO ACTION sunt identice. În MySQL, NO ACTION înseamnă de fapt RESTRICT. În standardul SQL, NO ACTION verifică la sfârșitul tranzacției.

Pot adăuga o cheie străină pe un tabel cu date existente?

Da, dar toate valorile din coloana copil trebuie să existe deja în tabelul părinte. Altfel, ALTER TABLE va eșua cu o eroare de integritate.

Când ar trebui să folosesc CASCADE vs RESTRICT?

CASCADE când copilul nu are sens fără părinte (ex: order_items la o comandă). RESTRICT când copilul poate exista independent sau când ștergerea accidentală ar fi gravă (ex: produse la o comandă).

Construit de dezvoltătorii Doda Browser, DodaZIP și Durga Antivirus Pro. Uneltele DodaTech se integrează nativ cu bazele de date pentru productivitate și securitate sporite.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro