Stile di domande e risposte
Bene, dopo aver ricercato e combattuto il problema per ore, ho scoperto che ci sono due modi per farlo, a seconda della struttura della tua tabella e se hai attivato le restrizioni per le chiavi esterne per mantenere l'integrità. Mi piacerebbe condividerlo in un formato pulito per risparmiare tempo alle persone che potrebbero trovarsi nella mia situazione.
Opzione 1: puoi permetterti di eliminare la riga
In altre parole, non hai una chiave esterna o, se le hai, il tuo motore SQLite è configurato in modo che non ci siano eccezioni di integrità. La strada da percorrere è INSERIRE O SOSTITUIRE . Se stai cercando di inserire / aggiornare un giocatore il cui ID esiste già, il motore SQLite eliminerà quella riga e inserirà i dati che fornisci. Ora viene la domanda: cosa fare per mantenere associato il vecchio ID?
Diciamo che vogliamo UPSERT con i dati user_name = 'steven' e age = 32.
Guarda questo codice:
INSERT INTO players (id, name, age)
VALUES (
coalesce((select id from players where user_name='steven'),
(select max(id) from drawings) + 1),
32)
Il trucco sta nella fusione. Restituisce l'id dell'utente "steven", se presente, e in caso contrario, restituisce un nuovo ID nuovo.
Opzione 2: non puoi permetterti di eliminare la riga
Dopo aver cercato la soluzione precedente, mi sono reso conto che nel mio caso ciò potrebbe finire per distruggere i dati, poiché questo ID funziona come una chiave esterna per un'altra tabella. Inoltre, ho creato la tabella con la clausola ON DELETE CASCADE , il che significherebbe che cancellerebbe i dati in silenzio. Pericoloso.
Quindi, prima ho pensato a una clausola IF, ma SQLite ha solo CASE . E questo CASE non può essere utilizzato (o almeno non l'ho gestito) per eseguire una query UPDATE se ESISTE (seleziona l'id dai giocatori dove user_name = 'steven') e INSERT se non lo è. No go.
E poi, finalmente, ho usato la forza bruta, con successo. La logica è, per ogni UPSERT che si desidera eseguire, eseguire prima un INSERT OR IGNORE per assicurarsi che ci sia una riga con il nostro utente, quindi eseguire una query UPDATE con esattamente gli stessi dati che si è tentato di inserire.
Stessi dati di prima: nome_utente = 'steven' ed età = 32.
-- make sure it exists
INSERT OR IGNORE INTO players (user_name, age) VALUES ('steven', 32);
-- make sure it has the right data
UPDATE players SET user_name='steven', age=32 WHERE user_name='steven';
E questo è tutto!
MODIFICARE
Come ha commentato Andy, il tentativo di inserire prima e poi aggiornare può portare ad attivare trigger più spesso del previsto. Questo non è a mio parere un problema di sicurezza dei dati, ma è vero che sparare eventi non necessari ha poco senso. Pertanto, una soluzione migliore sarebbe:
-- Try to update any existing row
UPDATE players SET age=32 WHERE user_name='steven';
-- Make sure it exists
INSERT OR IGNORE INTO players (user_name, age) VALUES ('steven', 32);