sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Qué sucede con los duplicados al insertar varias filas?

El INSERT simplemente insertará todas las filas y nada ocurrirá algo especial, a menos que tienes algún tipo de restricción no permitir valores duplicados/superpuestos (PRIMARY KEY , UNIQUE , CHECK o EXCLUDE restricción) - que no mencionó en su pregunta. Pero eso es lo que probablemente le preocupa.

Asumiendo un UNIQUE o restricción PK en (col1,col2) , se trata de un libro de texto UPSERT situación. Muchas preguntas y respuestas relacionadas para encontrar aquí.

Generalmente, si cualquiera se viola la restricción, se genera una excepción que (a menos que esté atrapada en una subtransacción como es posible en un lenguaje de procedimiento del lado del servidor como plpgsql) revertirá no solo la declaración, sino la transacción completa .

Sin escrituras simultáneas

Es decir:ninguna otra transacción intentará escribir en la misma tabla al mismo tiempo.

  • Excluye filas que ya están en la tabla con WHERE NOT EXISTS ... o cualquier otra técnica aplicable:

  • Seleccionar filas que no están presentes en otra tabla

  • Y no olvide eliminar los duplicados dentro el conjunto insertado también, que no ser excluido por el semi-anti-join WHERE NOT EXISTS ...

Una técnica para tratar con ambos a la vez sería EXCEPT :

INSERT INTO tbl (col1, col2)
VALUES
  (text 'v1', text 'v2')  -- explicit type cast may be needed in 1st row
, ('v3', 'v4')
, ('v3', 'v4')  -- beware of dupes in source
EXCEPT SELECT col1, col2 FROM tbl;

EXCEPT sin la palabra clave ALL pliega las filas duplicadas en el origen. Si sabe que no hay duplicados, o no desea retirar los duplicados en silencio, use EXCEPT ALL (o una de las otras técnicas). Ver:

  • Uso de la cláusula EXCEPT en PostgreSQL

Generalmente, si la tabla de destino es grande , WHERE NOT EXISTS en combinación con DISTINCT en la fuente probablemente será más rápido:

INSERT INTO tbl (col1, col2)
SELECT *
FROM  (
   SELECT DISTINCT *
   FROM  (
       VALUES
         (text 'v1', text'v2')
       , ('v3', 'v4')
       , ('v3', 'v4')  -- dupes in source
      ) t(c1, c2)
   ) t
WHERE NOT EXISTS (
   SELECT FROM tbl
   WHERE  col1 = t.c1 AND col2 = t.c2
   );

Si puede haber muchos duplicados, vale la pena doblarlos primero en la fuente. De lo contrario, use una subconsulta menos.

Relacionado:

  • Seleccionar filas que no están presentes en otra tabla

Con escrituras simultáneas

Utilice Postgres UPSERT implementación INSERT ... ON CONFLICT ... en Postgres 9.5 o posterior:

INSERT INTO tbl (col1,col2)
SELECT DISTINCT *  -- still can't insert the same row more than once
FROM  (
   VALUES
     (text 'v1', text 'v2')
   , ('v3','v4')
   , ('v3','v4')  -- you still need to fold dupes in source!
  ) t(c1, c2)
ON CONFLICT DO NOTHING;  -- ignores rows with *any* conflict!

Lectura adicional:

  • ¿Cómo usar RETURNING con ON CONFLICT en PostgreSQL?
  • ¿Cómo inserto una fila que contiene una clave externa?

Documentación:

  • El manual
  • La página de confirmación
  • La página wiki de Postgres

Respuesta de referencia de Craig para UPSERT problemas:

  • ¿Cómo UPSERT (COMBINAR, INSERTAR... EN ACTUALIZACIÓN DUPLICADA) en PostgreSQL?