2010-04-26 4 views
74

MySQL ha qualcosa di simile:SQLite INSERT - ON DUPLICATE KEY UPDATE

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

Per quanto ne so sto questa funzione non esiste in SQLite, quello che voglio sapere è se c'è qualche modo per archiviare lo stesso effetto senza dover eseguire due query. Inoltre, se questo non è possibile, che cosa preferisci:

  1. SELECT + (INSERT o UPDATE) o
  2. UPDATE (+ Ins se aggiornamento non riesce)

risposta

103
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).


MODIFICA: Un'altra grande soluzione: https://stackoverflow.com/a/4330694/89771.

+2

Solo per la registrazione, 'REPLACE' non è un'opzione. –

+1

Per quanto riguarda il collegamento "un'altra grande soluzione", prenderei anche in considerazione una risposta diversa alla stessa domanda: http://stackoverflow.com/a/418988/3650835 – KayakinKoder

16

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

+0

Grazie! @ Sam (http://stackoverflow.com/questions/418898/sqlite-upsert-not-insert-or-replace/418988#418988) sembra essere d'accordo con te. Preferisco anche questo approccio. –

+1

@codeholic dove posso ottenere la sintassi per questo metodo – Smith

+0

@Smith intendevo usare semplici istruzioni UPDATE e INSERT e controllare il valore di ritorno. – codeholic

-3

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

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

+0

Se i dati non sono così importanti, sì. Tuttavia, se viene utilizzato su un sito occupato in cui molti IP stanno colpendo il servizio, le istanze memcached potrebbero essere piene e causare la perdita di alcuni contenuti. Anche il backup di contenuti in memcached sarebbe interessante (se necessario). –

+0

@ElliotFoster Memcached può gestire quanti più dati della RAM viene lanciata (se si desidera persistenza, utilizzare quindi redis o membase). Se ricevi più di 1 milione di visitatori al giorno, probabilmente puoi permetterti di dare all'istanza di memcache più di 30MB di RAM (che credo sia l'impostazione predefinita). Tuttavia, può certamente gestire un carico molto più elevato di SQLite e MySQL per la quantità di memoria che gli viene assegnata - non c'è proprio alcun confronto. – Xeoncross

+0

Si prega di non confondere il mio commento come un voto contro memcache, in quanto penso che sia uno strumento fantastico. Come è redis (non posso parlare per membase, come non l'ho usato.) Tuttavia, memcache/redis non sono i negozi più affidabili. Sì, redis ha persistenza, ma i dati sono persistenti su disco su un intervallo (ultimo ho guardato) e memcache non del tutto. 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. –

5

La risposta corrente funzionerà solo in sqlite O mysql (a seconda se si utilizza OR o meno). Quindi, se vuoi la compatibilità cross dbms, il seguente ...

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

La risposta accettata funziona su SQLite (che era il mio obiettivo). 'REPLACE' funzionerà anche su SQLite, ma su MySQL resetterà sempre il contatore a 0 - mentre la query sarà portatile, il risultato finale sarà molto diverso. –

+0

Hai ragione, pensavo che l'OP cercasse qualcosa che fosse portatile. Realizzo REPLACE INTO non funzionerà con tutti i casi, specialmente dove è necessaria la conservazione PK, ma per molti casi. –

+0

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