INSERTAR SQLite - EN ACTUALIZACIÓN DE CLAVE DUPLICADA (UPSERT)

98

MySQL tiene algo como esto:

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

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

  1. SELECCIONAR + (INSERTAR o ACTUALIZAR) o
  2. ACTUALIZAR (+ INSERTAR si ACTUALIZAR falla )
Alix Axel
fuente

Respuestas:

31

Desde 3.24.0, SQLite también admite upsert , por lo que ahora puede simplemente escribir lo siguiente

INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON CONFLICT(ip) DO UPDATE SET hits = hits + 1;
szmate1618
fuente
3
Me preguntaba si puede hacer varias cosas upsertcomo esta en una transacción, es decir, con la executemany()función Python .
Radio controlado
117
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 CLAVE PRIMARIA).


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

dan04
fuente
2
Solo para que conste, REPLACEno es una opción.
Alix Axel
1
Con respecto al enlace "otra gran solución", también consideraría una respuesta diferente a la misma pregunta: stackoverflow.com/a/418988/3650835
KayakinKoder
19

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

codeholic
fuente
1
¡Gracias! @Sam ( stackoverflow.com/questions/418898/… ) parece estar de acuerdo contigo. También prefiero este enfoque.
Alix Axel
@Smith Me refiero a usar declaraciones simples de ACTUALIZAR e INSERTAR y verificar el valor de retorno.
Codeholic
Esto no tiene atomicidad, es posible que INSERT falle si se inserta algún otro proceso en el medio.
Robin Lavallée
7

La respuesta actual solo funcionará en sqlite OR mysql (dependiendo de si usa OR o no). Entonces, si desea compatibilidad cruzada con dbms, lo siguiente será suficiente ...

REPLACE INTO `visits` (ip, value) VALUES ($ip, 0);
Jacob Thomason
fuente
3
La respuesta aceptada funciona en SQLite (ese era mi objetivo). REPLACEtambién funcionará en SQLite, pero en MySQL siempre restablecerá el contador a 0; mientras que la consulta será portátil, el resultado final será muy diferente.
Alix Axel
Tienes razón, pensé que el OP estaba buscando algo que fuera portátil. Me doy cuenta de que REPLACE INTO no funcionará con todos los casos, especialmente cuando se necesita la conservación de PK, pero lo hará en muchos casos.
Jacob Thomason
Fallar limpiamente en lugar de descartar datos es una característica, no un error.
Tobu
-4

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

Es más rápido que MySQL y ahorra carga para que MySQL pueda concentrarse en otras cosas.

Xeoncross
fuente
Si los datos no son tan importantes, sí. Sin embargo, si esto se usa en un sitio ocupado donde muchas direcciones IP están llegando al servicio, las instancias de Memcached pueden llenarse y hacer que se elimine parte del contenido. Hacer una copia de seguridad del contenido de Memcached también sería interesante (si es necesario)
Elliot Foster
@ElliotFoster Memcached puede manejar tantos datos como la RAM que le arroje (si desea persistencia también, use redis o membase). Si recibe más de 1 millón de visitantes al día, probablemente pueda darse el lujo de darle a su instancia de Memcache más de 30 MB de RAM (que es el valor predeterminado, creo). Sin embargo, ciertamente puede manejar una carga mucho mayor que SQLite y MySQL por la cantidad de memoria que le da, simplemente no hay comparación.
Xeoncross
No confunda mi comentario con un voto en contra de Memcache, ya que creo 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 guardan en el disco en un intervalo (la última vez que miré) y Memcache no en absoluto. Como dije, si los datos no son importantes (o se pueden reproducir fácilmente), Memcache y la compañía son excelentes. La publicación original también preguntaba sobre sqlite, que es muy diferente de MySQL y probablemente significa que están limitados de otras maneras.
Elliot Foster
Puede configurar Redis para conservar los datos tan rápido como desee (en X segundos o Y en cambios).
Buffalo