Algunos servidores SQL tienen una característica que INSERT
se omite si viola una restricción de clave principal / única. Por ejemplo, MySQL tiene INSERT IGNORE
.
¿Cuál es la mejor manera de emular INSERT IGNORE
y ON DUPLICATE KEY UPDATE
con PostgreSQL?
database
postgresql
rules
gpilotino
fuente
fuente
ON DUPLICATE KEY UPDATE
en PgSQL 9.5 todavía es algo imposible, porque elON CLAUSE
equivalente de PgSQL requiere que proporcione el nombre de la restricción, mientras que MySQL podría capturar cualquier restricción sin la necesidad de definirlo. Esto me impide "emular" esta función sin tener que volver a escribir consultas.Respuestas:
Intenta hacer una ACTUALIZACIÓN. Si no modifica ninguna fila, eso significa que no existía, entonces haga una inserción. Obviamente, haces esto dentro de una transacción.
Por supuesto, puede envolver esto en una función si no desea poner el código adicional en el lado del cliente. También necesita un bucle para la rara condición de carrera en ese pensamiento.
Hay un ejemplo de esto en la documentación: http://www.postgresql.org/docs/9.3/static/plpgsql-control-structures.html , ejemplo 40-2 justo en la parte inferior.
Esa suele ser la forma más fácil. Puedes hacer algo de magia con las reglas, pero es probable que sea mucho más complicado. Recomendaría el enfoque de envoltura en función sobre eso cualquier día.
Esto funciona para una sola fila, o pocas filas, valores. Si está tratando con grandes cantidades de filas, por ejemplo, de una subconsulta, es mejor dividirla en dos consultas, una para INSERTAR y otra para ACTUALIZAR (como una unión / subselección apropiada, por supuesto, no es necesario escribir su principal filtrar dos veces)
fuente
INSERT ... ON CONFLICT DO NOTHING;
. Consulte también la respuesta stackoverflow.com/a/34639631/2091700 .MERGE
es un complemento seguro de concurrencia, a menos que tome una primera. La gente lo usa de esa manera, pero está mal.LOCK TABLE
Con PostgreSQL 9.5, esta es ahora una funcionalidad nativa (como MySQL ha tenido durante varios años):
...
fuente
Editar: en caso de que se haya perdido la respuesta de Warren, PG9.5 ahora tiene esto de forma nativa; hora de actualizar!
Sobre la base de la respuesta de Bill Karwin, para explicar cómo se vería un enfoque basado en reglas (transferencia desde otro esquema en el mismo DB y con una clave principal de varias columnas):
Nota: La regla se aplica a todas las
INSERT
operaciones hasta que se descarta, por lo que no es muy ad hoc.fuente
another_schema.my_table
contiene duplicados de acuerdo con las restricciones demy_table
?INSERT INTO "my_table" SELECT DISTINCT ON (pk_col_1, pk_col_2) * FROM the_tmp_table;
DELETE FROM my_table WHERE ctid IN (SELECT ctid FROM (SELECT ctid,ROW_NUMBER() OVER (PARTITION BY pk_col_1,pk_col_2) AS rn FROM my_table) AS dups WHERE dups.rn > 1);
Para aquellos de ustedes que tienen Postgres 9.5 o superior, la nueva sintaxis ON CONFLICT DOH NOTHING debería funcionar:
Para aquellos de nosotros que tenemos una versión anterior, esta combinación correcta funcionará en su lugar:
fuente
Unique violation: 7 ERROR: duplicate key value violates unique constraint
cuando setarget_table
insertó otra fila mientras se ejecutaba esta consulta, si sus claves, de hecho, se duplican entre sí. Creo que el bloqueotarget_table
ayudará, pero la concurrencia obviamente sufrirá.ON CONFLICT (field_one) DO NOTHING
Es la mejor parte de la respuesta.Para obtener la lógica de ignorar inserción , puede hacer algo como a continuación. Descubrí que simplemente insertar desde una instrucción select de valores literales funcionó mejor, luego puede enmascarar las claves duplicadas con una cláusula NOT EXISTS. Para obtener la actualización en lógica duplicada, sospecho que sería necesario un bucle pl / pgsql.
fuente
fuente
Parece que PostgreSQL admite un objeto de esquema llamado regla .
http://www.postgresql.org/docs/current/static/rules-update.html
Puede crear una regla
ON INSERT
para una tabla determinada, haciéndoloNOTHING
si existe una fila con el valor de clave principal dado, o haciendo que haga una enUPDATE
lugar deINSERT
si existe una fila con el valor de clave principal dado.No lo he intentado yo mismo, así que no puedo hablar por experiencia ni ofrecer un ejemplo.
fuente
Como @hanmari mencionó en su comentario. cuando se inserta en tablas de postgres, el conflicto on (..) no hacer nada es el mejor código para no insertar datos duplicados .:
La línea de código ON CONFLICT permitirá que la instrucción de inserción aún inserte filas de datos. El código de consulta y valores es un ejemplo de fecha insertada desde un Excel en una tabla db de postgres. Tengo restricciones agregadas a una tabla de postgres que uso para asegurarme de que el campo ID sea único. En lugar de ejecutar una eliminación en filas de datos que son iguales, agrego una línea de código sql que renumera la columna ID a partir de 1. Ejemplo:
Si mis datos tienen un campo de ID, no lo uso como ID principal / ID en serie, creo una columna de ID y la configuro en serie. Espero que esta información sea útil para todos. * No tengo título universitario en desarrollo / codificación de software. Todo lo que sé en codificación, lo estudio por mi cuenta.
fuente
Esta solución evita el uso de reglas:
pero tiene un inconveniente de rendimiento (ver PostgreSQL.org ):
fuente
En forma masiva, siempre puede eliminar la fila antes de la inserción. La eliminación de una fila que no existe no causa un error, por lo que se omite de forma segura.
fuente
DEFERRABLE INITIALLY DEFERRED
banderas.Para los scripts de importación de datos, para reemplazar "SI NO EXISTE", en cierto modo, hay una formulación un poco incómoda que, sin embargo, funciona:
fuente