SQLite INSERT - ON DUPLICATE KEY UPDATE (UPSERT)


98

MySQL ha qualcosa del genere:

INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON DUPLICATE KEY UPDATE hits = hits + 1;

Per quanto ne so questa funzionalità non esiste in SQLite, quello che voglio sapere è se esiste un modo per ottenere lo stesso effetto senza dover eseguire due query. Inoltre, se questo non è possibile, cosa preferisci:

  1. SELEZIONA + (INSERT o UPDATE) o
  2. UPDATE (+ INSERT se UPDATE fallisce )

Risposte:



117
INSERT OR IGNORE INTO visits VALUES ($ip, 0);
UPDATE visits SET hits = hits + 1 WHERE ip LIKE $ip;

Ciò richiede che la colonna "ip" abbia un vincolo UNIQUE (o PRIMARY KEY).


EDIT: un'altra ottima soluzione: https://stackoverflow.com/a/4330694/89771 .


2
Solo per la cronaca, REPLACEnon è un'opzione.
— Alix Axel

1
Per quanto riguarda il "un'altra grande soluzione", inserite Vorrei anche prendere in considerazione una risposta diversa alla stessa domanda: stackoverflow.com/a/418988/3650835
— KayakinKoder

19

Preferirei UPDATE (+ INSERT if UPDATE fails). Meno codice = meno bug.


1
Grazie! @ Sam ( stackoverflow.com/questions/418898/... ) sembra essere d'accordo con te. Anch'io preferisco questo approccio.
— Alix Axel

@ Smith Intendevo usare semplici istruzioni UPDATE e INSERT e controllare il valore di ritorno.
— codeholic

Questo non ha atomicità, è possibile che INSERT fallisca se qualche altro processo viene inserito nel mezzo.
— Robin Lavallée

7

La risposta corrente funzionerà solo in sqlite OR mysql (a seconda che tu usi OR o meno). Quindi, se vuoi la compatibilità cross dbms, quanto segue farà ...

REPLACE INTO `visits` (ip, value) VALUES ($ip, 0);

3
La risposta accettata funziona su SQLite (questo era il mio obiettivo). REPLACEfunzionerà anche su SQLite, ma su MySQL reimposterà sempre il contatore a 0 - mentre la query sarà portabile, il risultato finale sarà molto diverso.
— Alix Axel

Hai ragione, pensavo che l'OP stesse cercando qualcosa che fosse portatile. Mi rendo conto che REPLACE INTO non funzionerà con tutti i casi, specialmente dove è necessaria la conservazione PK, ma lo farà per molti casi.
— Jacob Thomason

Fallire in modo pulito invece di scartare i dati è una caratteristica, non un bug.
— Tobu

-4

Dovresti usare memcached per questo poiché è una singola chiave (l'indirizzo IP) che memorizza un singolo valore (il numero di visite). È possibile utilizzare la funzione di incremento atomico per assicurarsi che non vi siano condizioni di "gara".

È più veloce di MySQL e salva il carico in modo che MySQL possa concentrarsi su altre cose.


Se i dati non sono così importanti, sì. Tuttavia, se questo viene utilizzato su un sito occupato in cui molti IP stanno raggiungendo il servizio, le istanze memcached potrebbero riempirsi e causare la caduta di alcuni contenuti. Anche il backup dei contenuti memorizzati nella cache sarebbe interessante (se necessario)
— Elliot Foster

@ElliotFoster Memcached può gestire tanti dati quanto la RAM che gli lanci (se vuoi persitenza, usa anche redis o membase). Se ricevi oltre 1 milione di visitatori al giorno, probabilmente puoi permetterti di dare alla tua istanza di memcache più di 30 MB di ram (che è l'impostazione predefinita, credo). Tuttavia, può certamente gestire un carico molto più elevato di SQLite e MySQL per la quantità di memoria che gli dai - semplicemente non c'è confronto.
— Xeoncross

Per favore, non confondere il mio commento con un voto contro memcache, poiché penso che sia uno strumento fantastico. Come è redis (non posso parlare per membase, poiché non l'ho usato.) Tuttavia, memcache / redis non sono i negozi più affidabili. Sì, redis ha persistenza, ma i dati vengono conservati su disco su un intervallo (l'ultima volta che ho guardato) e memcache per niente. Come ho detto, se i dati non sono importanti (o possono essere riprodotti facilmente), memcache e company sono fantastici. Il post originale chiedeva anche di sqlite, che è molto diverso da MySQL e probabilmente significa che sono limitati in altri modi.
— Elliot Foster

È possibile configurare Redis per rendere persistenti i dati alla velocità desiderata (al numero X di secondi o al numero Y di modifiche).
— Buffalo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.