INSERT aggiunge righe a una tabella
INSERT è l'istruzione che usi per mettere nuove righe in una tabella. La forma è breve e prevedibile:
Tre parti da notare:
INSERT INTO books: la tabella di destinazione.(title, author, year): le colonne per cui fornisci i valori.VALUES (...): i valori, nello stesso ordine dell'elenco di colonne.
id non è nell'elenco di colonne, quindi SQLite lo assegna in automatico (è una INTEGER PRIMARY KEY, che prende il rowid). Qualsiasi colonna che salti assume il suo valore predefinito, oppure NULL se non ne ha uno.
Elenca sempre le colonne
Puoi omettere l'elenco di colonne e fornire valori per ogni colonna nell'ordine di dichiarazione:
-- Funziona, ma è fragile:
INSERT INTO books VALUES (NULL, 'Dune', 'Frank Herbert', 1965);
Non farlo. Appena qualcuno aggiunge una colonna a books, ogni istruzione del genere si rompe o comincia a inserire valori nella colonna sbagliata. Scrivi le colonne per esteso:
Gli elenchi di colonne espliciti sono una forma di documentazione: rendono l'istruzione leggibile da sola, senza dover andare a cercare la definizione della tabella.
Inserire più righe
Puoi inserire più righe in un'unica istruzione elencando più tuple di valori:
È più pulito di tre istruzioni INSERT separate, e SQLite tratta il tutto come un'unica istruzione. Il vero guadagno di prestazioni nei caricamenti massivi, però, arriva dal racchiudere gli inserimenti in una transazione: ne parliamo subito.
Inserimenti massivi: racchiudili in una transazione
Per impostazione predefinita, ogni INSERT è una transazione a sé. SQLite esegue un fsync alla fine di ciascuna, ed è questo che rende lenti i cicli ingenui, non gli inserimenti in sé.
Raggruppali:
Un solo fsync invece di cinque. Con migliaia di righe la differenza può essere di due o tre ordini di grandezza. Se qualcosa all'interno fallisce, ROLLBACK annulla l'intero blocco.
Questa è la ricetta per gli inserimenti massivi. Usala sia che chiami SQLite da Python, da Node o da Rust: racchiudi il tuo ciclo tra BEGIN e COMMIT.
INSERT ... SELECT: copiare da un'altra tabella
Puoi popolare una tabella a partire da una query invece che da valori letterali:
Le colonne della SELECT vengono abbinate per posizione all'elenco di colonne dell'INSERT. I nomi non devono coincidere, l'ordine sì. È il modo standard per archiviare righe, costruire tabelle di report o copiare un sottoinsieme di dati durante una migrazione.
DEFAULT VALUES e colonne omesse
Se una colonna ha una clausola DEFAULT, puoi lasciarla fuori dall'elenco di colonne e SQLite inserisce il valore predefinito:
created_at riceve il timestamp corrente perché non ne abbiamo fornito uno. Se vuoi una riga fatta solo di valori predefiniti, utile per righe segnaposto, usa la forma DEFAULT VALUES:
Due nuove righe, entrambe con value = 0 e id assegnati automaticamente.
INSERT OR IGNORE: saltare i duplicati
Quando una riga violerebbe un vincolo UNIQUE o PRIMARY KEY, il comportamento predefinito è interrompere l'istruzione con un errore:
Error: UNIQUE constraint failed: users.email
INSERT OR IGNORE lo sostituisce con "salta in silenzio la riga problematica":
Sopravvivono tre righe. Il duplicato viene scartato senza errori. È il modo idiomatico di SQLite per esprimere "inserisci se non esiste" con dati di seed semplici: nessuna SELECT separata per controllare prima, nessuna gestione delle eccezioni.
INSERT OR REPLACE: sovrascrivere i duplicati
INSERT OR REPLACE elimina la riga in conflitto e inserisce quella nuova al suo posto:
Attenzione a una cosa: REPLACE è DELETE + INSERT, non UPDATE. Se la riga eliminata aveva chiavi esterne che puntavano a lei con ON DELETE CASCADE, vengono eliminati anche quei figli. E qualsiasi colonna che non elenchi nel nuovo INSERT torna al suo valore predefinito: non conserva il valore precedente.
Per la maggior parte dei casi "aggiorna se esiste, inserisci se no", quello che ti serve davvero è un vero upsert con ON CONFLICT ... DO UPDATE. Ha una pagina tutta sua.
Riepilogo veloce
INSERT INTO table (cols) VALUES (...): la forma base. Elenca sempre le colonne.- Gli inserimenti di più righe usano tuple separate da virgole dopo
VALUES. - Per i veri caricamenti massivi, racchiudi gli inserimenti tra
BEGINeCOMMIT. INSERT INTO ... SELECT ...copia righe da una query.DEFAULT VALUEScrea una riga solo con i valori predefiniti; anche le colonne omesse assumono il loro valore predefinito.INSERT OR IGNOREsalta le righe in conflitto;INSERT OR REPLACEle sovrascrive (con un delete + insert).
Prossimo passo: UPDATE
Inserire righe è metà del lavoro. L'altra metà è modificare righe che esistono già: incrementare un contatore, correggere un refuso, segnare un ordine come spedito. È UPDATE, e ha le sue abitudini da imparare bene (soprattutto la clausola WHERE). È il prossimo argomento.
Domande frequenti
Come inserisco una riga in SQLite?
Usa INSERT INTO table (col1, col2) VALUES (val1, val2);. Elencare le colonne è facoltativo ma fortemente consigliato: l'istruzione continua a funzionare anche se in futuro la tabella riceve una nuova colonna. Senza elenco di colonne, devi fornire un valore per ogni colonna nell'ordine di dichiarazione.
Come inserisco più righe insieme in SQLite?
Metti più tuple tra parentesi dopo VALUES, separate da virgole: INSERT INTO t (a, b) VALUES (1, 2), (3, 4), (5, 6);. Per i veri caricamenti massivi (migliaia di righe), racchiudi gli inserimenti in un'unica transazione con BEGIN e COMMIT: è da lì che arriva la velocità, non dalla sintassi a più righe in sé.
Cosa fa INSERT OR IGNORE in SQLite?
INSERT OR IGNORE salta le righe che violerebbero un vincolo UNIQUE, PRIMARY KEY o NOT NULL invece di sollevare un errore. La riga in conflitto viene scartata in silenzio e il resto dell'istruzione prosegue. Usalo quando vuoi un comportamento 'inserisci se non c'è già' senza un controllo di esistenza separato.
Perché ottengo 'UNIQUE constraint failed' con INSERT?
SQLite ha trovato una riga esistente con lo stesso valore in una colonna UNIQUE o PRIMARY KEY. O il valore è davvero un duplicato, o stai rieseguendo uno script di seed. Passa a INSERT OR IGNORE per saltare i duplicati, a INSERT OR REPLACE per sovrascriverli, oppure usa ON CONFLICT ... DO UPDATE (upsert) per un controllo più fine.