INSERISCI SE NON ESISTE ALTRO AGGIORNAMENTO?

Ho trovato alcune “sarebbero” soluzioni per il classico “Come inserire un nuovo record o aggiornarne uno se già esiste” ma non riesco a far funzionare nessuno di loro in SQLite.

Ho una tabella definita come segue:

CREATE TABLE Book ID INTEGER PRIMARY KEY AUTOINCREMENT, Name VARCHAR(60) UNIQUE, TypeID INTEGER, Level INTEGER, Seen INTEGER 

Quello che voglio fare è aggiungere un record con un nome univoco. Se il nome esiste già, voglio modificare i campi.

Qualcuno può dirmi come farlo per favore?

Dai un’occhiata a http://sqlite.org/lang_conflict.html .

Vuoi qualcosa come:

 insert or replace into Book (ID, Name, TypeID, Level, Seen) values ((select ID from Book where Name = "SearchName"), "SearchName", ...); 

Notare che qualsiasi campo non incluso nell’elenco di inserimento verrà impostato su NULL se la riga esiste già nella tabella. Questo è il motivo per cui esiste una sottoselezione per la colonna ID : nel caso di sostituzione l’istruzione lo imposterà su NULL e quindi verrà assegnato un nuovo ID.

Questo approccio può essere utilizzato anche se si desidera lasciare valori del campo particolari da soli se la riga è nella casella di sostituzione, ma impostare il campo su NULL nel caso di inserimento.

Ad esempio, supponendo che tu voglia lasciare solo Seen :

 insert or replace into Book (ID, Name, TypeID, Level, Seen) values ( (select ID from Book where Name = "SearchName"), "SearchName", 5, 6, (select Seen from Book where Name = "SearchName")); 

È necessario utilizzare il comando INSERT OR IGNORE seguito da un comando UPDATE : Nell’esempio seguente, “name” è una chiave primaria:

esempio:

 INSERT OR IGNORE INTO my_table (name,age) VALUES('Karen',34) UPDATE my_table SET age = 34 WHERE name='Karen' 

Il primo comando inserirà il record. Se il record esiste, ignorerà l’errore causato dal conflitto con una chiave primaria esistente.

Il secondo comando aggiornerà il record (che ora esiste sicuramente)

È necessario impostare un vincolo sulla tabella per triggersre un ” conflitto ” che verrà risolto eseguendo una sostituzione:

 CREATE TABLE data (id INTEGER PRIMARY KEY, event_id INTEGER, track_id INTEGER, value REAL); CREATE UNIQUE INDEX data_idx ON data(event_id, track_id); 

Quindi puoi emettere:

 INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 3); INSERT OR REPLACE INTO data VALUES (NULL, 2, 2, 3); INSERT OR REPLACE INTO data VALUES (NULL, 1, 2, 5); 

Il “SELECT * FROM data” ti darà:

 2|2|2|3.0 3|1|2|5.0 

Notare che data.id è “3” e non “1” perché REPLACE esegue un CANC e INSERT, non un UPDATE. Ciò significa anche che è necessario assicurarsi di definire tutte le colonne necessarie o ottenere valori NULL imprevisti.

Innanzitutto aggiornalo. Se il conteggio delle righe è interessato = 0, inserirlo. È il più semplice e adatto a tutti i RDBMS .

INSERT OR REPLACE sostituirà gli altri campi ( TypeID , Level ) al valore predefinito.

 INSERT OR REPLACE INTO book(id, name) VALUES(1001, 'Programming') 

Sto usando questo

 INSERT OR IGNORE INTO book(id) VALUES(1001); UPDATE book SET name = 'Programming' WHERE id = 1001; 

Puoi anche usare

 INSERT OR REPLACE INTO book (id, name) VALUES (1001, 'Programming', (SELECT typeid FROM book WHERE id = 1001), (SELECT level FROM book WHERE id = 1001), ) 

ma penso che il primo metodo sia più facile da leggere

Se non si dispone di una chiave primaria, è ansible inserire se non esiste, quindi eseguire un aggiornamento. La tabella deve contenere almeno una voce prima di utilizzarla.

 INSERT INTO Test (id, name) SELECT 101 as id, 'Bob' as name FROM Test WHERE NOT EXISTS(SELECT * FROM Test WHERE id = 101 and name = 'Bob') LIMIT 1; Update Test SET id='101' WHERE name='Bob'; 

Credo che tu voglia UPSERT .

“INSERIRE O SOSTITUIRE” senza l’inganno aggiuntivo in quella risposta, reimposterà qualsiasi campo che non specifichi a NULL o altro valore predefinito. (Questo comportamento di INSERT O REPLACE è diverso da UPDATE, è esattamente come INSERT, perché in realtà è INSERT, tuttavia se ciò che si desidera è UPDATE-if-exists probabilmente si desidera la semantica UPDATE e sarà spiacevolmente sorpreso dal risultato effettivo.)

L’inganno dall’implementazione UPSERT suggerita consiste fondamentalmente nell’utilizzare INSERT O REPLACE, ma specificare tutti i campi, utilizzando clausole SELECT incorporate per recuperare il valore corrente per i campi che non si desidera modificare.

Penso che valga la pena sottolineare che qui può esserci qualche comportamento inaspettato se non capisci a fondo come interagiscono PRIMARY KEY ed UNIQUE .

Ad esempio, se si desidera inserire un record solo se il campo NAME non è attualmente in uso, e se lo è, si desidera che un’eccezione di limitazione si attivi per dirlo, quindi INSERT O REPLACE non genererà ed eccezione e invece lo farà risolvere il vincolo UNIQUE stesso sostituendo il record in conflitto (il record esistente con lo stesso NOME ). Gaspard’s lo dimostra molto bene nella sua risposta sopra.

Se si desidera triggersre un’eccezione di vincolo, è necessario utilizzare un’istruzione INSERT e fare affidamento su un comando UPDATE separato per aggiornare il record dopo aver riconosciuto che il nome non è stato preso.