2010-04-26 16 views
74

MySQL tiene algo como esto:SQLite INSERT - ON DUPLICATE KEY UPDATE

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

Por lo que yo estoy sé esta característica no existe en SQLite, lo que quiero saber es si hay alguna manera para archivar el mismo efecto sin tener que ejecutar dos consultas. Además, si esto no es posible, ¿qué prefieres:

  1. SELECT + (INSERT o UPDATE) o
  2. ACTUALIZACIÓN (+ Insert si falla la actualización)

Respuesta

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

Esto requiere que la columna "ip" tenga una restricción ÚNICA (o PRIMARY KEY).


EDIT: Otra gran solución: https://stackoverflow.com/a/4330694/89771.

+2

Solo para el registro, 'REPLACE' no es una opción. –

+1

En cuanto al enlace "otra gran solución", también consideraría una respuesta diferente a la misma pregunta: http://stackoverflow.com/a/418988/3650835 – KayakinKoder

16

Prefiero UPDATE (+ INSERT if UPDATE fails). Menos código = menos errores.

+0

¡Gracias! @Sam (http://stackoverflow.com/questions/418898/sqlite-upsert-not-insert-or-replace/418988#418988) parece estar de acuerdo con usted. Yo también prefiero este enfoque. –

+1

@codeholic donde puedo obtener la sintaxis para este método – Smith

+0

@Smith Me refería al uso de instrucciones simples UPDATE e INSERT y la comprobación del valor de retorno. – codeholic

-3

Debe usar memcached para esto ya que es una sola clave (la dirección IP) que almacena un único valor (el número de visitas). Puede usar la función de incremento atómico para asegurarse de que no haya condiciones de "carrera".

Es más rápido que MySQL y guarda la carga para que MySQL pueda enfocarse en otras cosas.

+0

Si los datos no son tan importantes, sí. Sin embargo, si esto se está utilizando en un sitio ocupado donde muchas direcciones IP están activando el servicio, las instancias de Memcached pueden llenarse y provocar que se descarte algo de contenido. También sería interesante hacer una copia de seguridad de los contenidos almacenados en memoria (si es necesario). –

+0

@ElliotFoster Memcached puede manejar tantos datos como la RAM que le arroja (si también desea utilizar redis o membase). Si recibe más de 1 millón de visitantes al día, probablemente pueda permitirse dar a su instancia de Memcache más de 30 MB de memoria RAM (que es lo que creo que es el predeterminado). Sin embargo, ciertamente puede manejar una carga mucho más alta que SQLite y MySQL por la cantidad de memoria que le da, simplemente no hay comparación. – Xeoncross

+0

No confundas mi comentario como voto en contra de Memcache, ya que considero que es una herramienta fantástica. Como es redis (no puedo hablar por membase, ya que no lo he usado). Sin embargo, Memcache/Redis no son las tiendas más confiables. Sí, redis tiene persistencia, pero los datos se conservan en el disco en un intervalo (último que miré) y Memcache en absoluto. Como dije, si los datos no son importantes (o se pueden reproducir fácilmente), Memcache y la compañía son geniales. La publicación original también preguntaba por sqlite, que es muy diferente de MySQL y probablemente significa que están limitadas de otras maneras. –

5

La respuesta actual solo funcionará en sqlite O mysql (dependiendo de si usa O o no). Por lo tanto, si desea compatibilidad cross dbms, lo siguiente será ...

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

La respuesta aceptada funciona en SQLite (ese era mi objetivo). 'REPLACE' también funcionará en SQLite, pero en MySQL siempre restablecerá el contador a 0, mientras que la consulta será portable, el resultado final será muy diferente. –

+0

Tienes razón, pensé que OP estaba buscando algo portátil. Me doy cuenta de que REPLACE INTO no funcionará en todos los casos, especialmente cuando se necesita preservación de PK, pero lo hará en muchos casos. –

+0

Fallar limpiamente en lugar de descartar datos es una característica, no un error. – Tobu

Cuestiones relacionadas