Ce face INSERT OR IGNORE / OR REPLACE
Când o comandă încalcă o constrângere UNIQUE, NOT NULL, CHECK sau PRIMARY KEY, SQLite aplică un „algoritm de rezolvare a conflictului”. Implicit este ABORT: comanda curentă este anulată (rândurile pe care le-a modificat deja revin la valoarea de dinainte), dar tranzacția rămâne deschisă. Cu INSERT OR ... sau UPDATE OR ... alegi alt algoritm doar pentru acea comandă.
IGNORE sare peste rândul cu probleme și continuă cu celelalte. REPLACE șterge rândurile care intră în conflict și pune rândul nou în locul lor; pentru NOT NULL folosește valoarea implicită a coloanei. FAIL oprește comanda, dar păstrează modificările făcute deja de ea, iar ROLLBACK anulează toată tranzacția. REPLACE INTO este o prescurtare pentru INSERT OR REPLACE INTO.
Algoritmul poate fi scris și direct în definiția tabelului, de exemplu UNIQUE ON CONFLICT IGNORE. Atunci se aplică la fiecare INSERT care nu cere explicit altceva. Aceasta este o extensie SQLite; în alte baze de date nu există.
Parametri
| Parametru | Descriere |
|---|---|
ABORT |
Implicit. Anulează modificările comenzii curente și dă eroare; tranzacția continuă. |
FAIL |
Dă eroare, dar păstrează rândurile modificate deja de aceeași comandă. |
IGNORE |
Sare peste rândul care produce conflictul, fără eroare. |
REPLACE |
Șterge rândul vechi care intră în conflict și inserează rândul nou. |
ROLLBACK |
Dă eroare și anulează toată tranzacția curentă. |
Exemple
Exemplele de pe această pagină pornesc de la datele de mai jos. Rulează mai întâi acest cod, apoi exemplul.
CREATE TABLE elevi (
cod TEXT PRIMARY KEY,
nume TEXT NOT NULL,
clasa TEXT,
nota INTEGER
);
INSERT INTO elevi VALUES
('E01', 'Ana Ionescu', '9A', 10),
('E02', 'Mihai Popa', '9A', 8),
('E03', 'Ioana Rusu', '9B', 9);
Exemplul 1: OR IGNORE: inserează doar rândurile noi
Codul E01 există deja, așa că acel rând este sărit. E04 este nou și ajunge în tabel. changes() confirmă că s-a inserat un singur rând.
INSERT OR IGNORE INTO elevi VALUES
('E01', 'Alt nume', '9C', 5),
('E04', 'Radu Stan', '9B', 7);
SELECT changes() AS inserate;
SELECT * FROM elevi ORDER BY cod;
Rezultat
╭──────────╮
│ inserate │
╞══════════╡
│ 1 │
╰──────────╯
╭─────┬─────────────┬───────┬──────╮
│ cod │ nume │ clasa │ nota │
╞═════╪═════════════╪═══════╪══════╡
│ E01 │ Ana Ionescu │ 9A │ 10 │
│ E02 │ Mihai Popa │ 9A │ 8 │
│ E03 │ Ioana Rusu │ 9B │ 9 │
│ E04 │ Radu Stan │ 9B │ 7 │
╰─────┴─────────────┴───────┴──────╯
Exemplul 2: OR REPLACE înlocuiește tot rândul
Am dat doar cod și nume. Rândul vechi E02 a fost șters, iar cel nou are clasa și nota goale (NULL). Un upsert cu ON CONFLICT DO UPDATE ar fi păstrat clasa și nota.
INSERT OR REPLACE INTO elevi (cod, nume) VALUES ('E02', 'Mihai Popa');
SELECT * FROM elevi ORDER BY cod;
Rezultat
╭─────┬─────────────┬───────┬──────╮
│ cod │ nume │ clasa │ nota │
╞═════╪═════════════╪═══════╪══════╡
│ E01 │ Ana Ionescu │ 9A │ 10 │
│ E02 │ Mihai Popa │ │ │
│ E03 │ Ioana Rusu │ 9B │ 9 │
╰─────┴─────────────┴───────┴──────╯
Exemplul 3: Regula de conflict pusă în tabel
Coloana email are UNIQUE ON CONFLICT IGNORE, deci adresa repetată este ignorată fără ca INSERT să mai ceară OR IGNORE.
CREATE TABLE abonati (email TEXT UNIQUE ON CONFLICT IGNORE);
INSERT INTO abonati VALUES ('ana@exemplu.ro');
INSERT INTO abonati VALUES ('vlad@exemplu.ro');
INSERT INTO abonati VALUES ('ana@exemplu.ro');
SELECT rowid, email FROM abonati;
Rezultat
╭───────┬─────────────────╮
│ rowid │ email │
╞═══════╪═════════════════╡
│ 1 │ ana@exemplu.ro │
│ 2 │ vlad@exemplu.ro │
╰───────┴─────────────────╯
Greșeli frecvente
- Folosești
OR REPLACEpe un tabel referit prin chei străine. Rândul vechi este șters, deci cuPRAGMA foreign_keys = ONse aplicăON DELETE(de exempluCASCADEșterge și rândurile copil). - Te bazezi pe
OR IGNOREși nu mai vezi greșelile. Ignoră și încălcărileNOT NULLsauCHECK, nu doar dublurile; un rând invalid dispare în tăcere. - Crezi că
OR REPLACEpăstreazărowid-ul. Rândul nou poate primi altrowiddacă nu dai cheia explicit.
Comenzi înrudite
INSERT ... ON CONFLICT (upsert): Inserează un rând sau, dacă cheia există deja, actualizează rândul existent (ori nu face nimic), într-o singură comandă.RETURNING: Face ca INSERT, UPDATE sau DELETE să returneze rândurile modificate, de exemplu id-ul generat, fără un SELECT separat.BEGIN, COMMIT, ROLLBACK: Grupează mai multe modificări într-o tranzacție: fie se salvează toate cu COMMIT, fie niciuna cu ROLLBACK.PRAGMA foreign_keys: Pornește verificarea cheilor străine. În SQLite este oprită implicit și trebuie pornită la fiecare conexiune.