Menu

Trigger in SQLite: CREATE TRIGGER, BEFORE/AFTER e OLD/NEW

Come funzionano i trigger in SQLite: BEFORE e AFTER, INSTEAD OF sulle viste, i riferimenti alle righe OLD e NEW e quando i trigger sono lo strumento giusto.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Un trigger esegue SQL in automatico

Un trigger è un blocco di SQL memorizzato che si attiva ogni volta che su una certa tabella avviene un certo evento. Lo scrivi una volta sola. Al "quando" ci pensa SQLite.

La forma:

Non abbiamo mai scritto un INSERT esplicito in price_history. L'ha fatto il trigger. Ogni futuro aggiornamento del prezzo verrà registrato allo stesso modo, che arrivi dalla CLI, da uno script o da un'app.

Anatomia di CREATE TRIGGER

Leggi la sintassi pezzo per pezzo:

CREATE TRIGGER trigger_name
{ BEFORE | AFTER | INSTEAD OF } { INSERT | UPDATE [ OF column_list ] | DELETE }
ON table_name
[ FOR EACH ROW ]
[ WHEN condition ]
BEGIN
    -- una o più istruzioni
END;
  • Momento: BEFORE viene eseguito prima della modifica, AFTER dopo, INSTEAD OF la sostituisce (solo sulle viste).
  • Evento: quale operazione lo attiva. UPDATE OF col1, col2 restringe gli aggiornamenti a colonne specifiche.
  • Tabella: la tabella osservata.
  • FOR EACH ROW: SQLite supporta solo trigger a livello di riga, quindi è implicito. Puoi scriverlo per chiarezza; non cambia nulla.
  • WHEN: una condizione facoltativa. Il corpo del trigger viene eseguito solo se è vera.
  • Corpo: una o più istruzioni tra BEGIN ed END. Ognuna deve terminare con un punto e virgola.

Questa è tutta la grammatica. La maggior parte dei trigger reali occupa da cinque a dieci righe.

OLD e NEW: la riga che cambia

Dentro il corpo, due pseudo righe ti fanno vedere i dati:

  • NEW: la riga in arrivo. Disponibile nei trigger INSERT e UPDATE.
  • OLD: la riga esistente. Disponibile nei trigger UPDATE e DELETE.

Un trigger DELETE ha solo OLD. Un trigger INSERT ha solo NEW. Un trigger UPDATE li ha entrambi.

La riga eliminata non c'è più in accounts, ma i suoi dati sono stati salvati in deletions prima che sparisse.

BEFORE: validare o sistemare la riga

I trigger BEFORE vengono eseguiti prima che la modifica della riga arrivi su disco. Sono comodi per sollevare un errore o normalizzare i dati:

Il secondo INSERT viene interrotto prima che venga scritta qualsiasi riga. RAISE(ABORT, '...') annulla l'istruzione corrente e fa rollback fino al suo inizio; RAISE(FAIL, ...), RAISE(ROLLBACK, ...) e RAISE(IGNORE) ti danno un controllo più fine su cosa succede.

Per la pura validazione dei dati, preferisci i vincoli CHECK: sono dichiarativi e l'ottimizzatore li conosce. Ricorri a un trigger BEFORE quando la regola deve guardare altre tabelle o fare qualcosa che un CHECK non riesce a esprimere.

WHEN: trigger condizionali

Una clausola WHEN filtra quali modifiche di riga attivano davvero il corpo. Viene valutata per ogni riga, dopo che OLD e NEW sono stati associati:

Il primo ordine non passa la soglia. Gli altri due sì. Senza la clausola WHEN, ogni insert avrebbe scritto in big_orders e dovresti filtrare in lettura.

INSTEAD OF: rendere scrivibile una vista

Le viste per impostazione predefinita sono in sola lettura. Un trigger INSTEAD OF intercetta una scrittura su una vista ed esegue il tuo SQL al suo posto, di solito traducendola in scritture sulle tabelle sottostanti:

L'applicazione parla con la vista come se fosse una tabella. Il trigger si occupa dietro le quinte di dividere il nome in first_name e last_name.

Elencare ed eliminare i trigger

I trigger stanno in sqlite_master insieme a tabelle e indici:

DROP TRIGGER IF EXISTS name; è la forma sicura. Eliminare la tabella su cui si trova un trigger elimina automaticamente anche il trigger: non serve fare pulizia prima.

Insidie da conoscere

Alcune cose fanno male la prima volta:

  • I trigger si attivano per riga, non per istruzione. Un UPDATE che tocca 1.000 righe attiva il trigger 1.000 volte. Se il corpo stesso è costoso, il conto sale in fretta.
  • I trigger vengono eseguiti dentro la transazione circostante. Se l'istruzione esterna fa rollback, anche le scritture del trigger vengono annullate. Di solito è quello che vuoi, ma significa che un trigger non è una scappatoia per "registra questo in ogni caso".
  • I trigger ricorsivi sono disattivati per impostazione predefinita. Un trigger che modifica la stessa tabella non si riattiva da solo, a meno che tu non imposti PRAGMA recursive_triggers = ON;. Lascialo disattivato se non hai un motivo preciso.
  • Le scritture lato applicazione possono aggirarli, ma solo saltando il database. Finché ogni scrittura passa da SQLite, il trigger verrà eseguito. Anche gli ORM che raggruppano le operazioni con SQL grezzo li attivano.
  • Non sparpagliare la logica di business su tanti trigger. Sono invisibili dal punto di chiamata: chi sta cercando di capire "perché è comparsa questa riga?" deve andare a frugare in sqlite_master. Usali per le questioni trasversali (log di audit, colonne derivate, viste scrivibili) e tieni il resto nel codice dell'applicazione.

Un esempio realistico di log di audit

Mettiamo insieme gli schemi visti: tracciare ogni modifica a una tabella posts:

Un solo trigger tiene aggiornato updated_at e scrive una riga di audit, tutto in un unico punto. Il codice dell'applicazione che esegue l'UPDATE non ha bisogno di sapere che nessuna delle due cose esiste.

Prossimo passo: supporto JSON

I trigger gestiscono l'automazione attorno agli eventi sulle righe. Il prossimo tassello di SQLite avanzato è quello che puoi memorizzare dentro una riga: il JSON. SQLite ha un set completo di funzioni JSON per interrogare e aggiornare dati strutturati senza uscire da SQL, ed è la prossima pagina.

Domande frequenti

Cos'è un trigger in SQLite?

Un trigger è un blocco di SQL che viene eseguito automaticamente quando su una tabella avviene un evento specifico: un INSERT, un UPDATE o un DELETE. Lo definisci una volta con CREATE TRIGGER e SQLite lo attiva per te ogni volta che l'evento si verifica. È il modo per tenere log di audit, mantenere colonne derivate o imporre regole senza affidarsi alla memoria dell'applicazione.

Che differenza c'è tra i trigger BEFORE, AFTER e INSTEAD OF?

BEFORE viene eseguito prima che la modifica della riga sia applicata: utile per validare o sistemare la riga. AFTER viene eseguito dopo che la modifica è avvenuta: utile per il logging o per sincronizzare altre tabelle. INSTEAD OF funziona solo sulle viste e sostituisce completamente l'operazione prevista, permettendoti di rendere scrivibile una vista.

Come faccio riferimento alla riga modificata dentro un trigger?

Usa NEW.column per la riga in arrivo con INSERT e UPDATE, e OLD.column per la riga esistente con UPDATE e DELETE. I trigger INSERT vedono solo NEW, i trigger DELETE solo OLD e i trigger UPDATE li vedono entrambi. Questi riferimenti valgono per la riga che si sta elaborando in quel momento.

Come elenco o elimino i trigger in SQLite?

I trigger stanno in sqlite_master: SELECT name, tbl_name FROM sqlite_master WHERE type = 'trigger'; li mostra tutti. Per eliminarne uno usa DROP TRIGGER trigger_name;, oppure DROP TRIGGER IF EXISTS trigger_name; se non sei sicuro che esista. Eliminare una tabella elimina anche i suoi trigger.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA