PostgreSQL INSERT ON CONFLICT UPDATE (upsert) usa todos los valores excluidos

142

Cuando está insertando una fila (PostgreSQL> = 9.5), y desea que el posible INSERT sea exactamente igual a la posible ACTUALIZACIÓN, puede escribirlo así:

INSERT INTO tablename (id, username, password, level, email) 
                VALUES (1, 'John', 'qwerty', 5, '[email protected]') 
ON CONFLICT (id) DO UPDATE SET 
  id=EXCLUDED.id, username=EXCLUDED.username,
  password=EXCLUDED.password, level=EXCLUDED.level,email=EXCLUDED.email

¿Hay un camino más corto? Solo para decir: use todos los valores EXCLUDE.

En SQLite solía hacer:

INSERT OR REPLACE INTO tablename (id, user, password, level, email) 
                        VALUES (1, 'John', 'qwerty', 5, '[email protected]')
Sebastian
fuente
43
No es una respuesta real, pero puede usar una notación ligeramente breve: INSERT INTO tablename (id, username, password, level, email) VALUES (1, 'John', 'qwerty', 5, '[email protected]') ON CONFLICT (id) DO UPDATE SET (username, password, level, email) = (EXCLUDED.username, EXCLUDED.password, EXCLUDED.level, EXCLUDED.email).casi lo mismo, pero fácil de copiar / pegar / administrar la lista de columnas
potro
Otra opción es usar columnas jsonb y de esa manera no tendrá que preocuparse por las columnas
j será el

Respuestas:

162

Postgres no ha implementado un equivalente a INSERT OR REPLACE. De los ON CONFLICTdocumentos (énfasis mío):

Puede ser NO HACER NADA o una cláusula DO UPDATE que especifique los detalles exactos de la acción UPDATE que se realizará en caso de conflicto.

Aunque no le da una abreviatura para el reemplazo, se ON CONFLICT DO UPDATEaplica de manera más general, ya que le permite establecer nuevos valores basados ​​en datos preexistentes. Por ejemplo:

INSERT INTO users (id, level)
VALUES (1, 0)
ON CONFLICT (id) DO UPDATE
SET level = users.level + 1;
Kristján
fuente
3
Como advertencia, la "actualización" no es semánticamente idéntica a la "fusión" del estándar SQL, aunque generalmente se puede usar en los mismos lugares. Tuve un caso en el que esperaba que la "actualización en conflicto" entrara en acción, pero el problema exacto en el inserto no causó que se iniciara la actualización (que habría reparado el registro dañado).
pojo-guy
2
¿Puede ampliar "pero el problema exacto en el inserto no causó la actualización"?
MrR
@ pojo-guy - No creo que haya visto la pregunta de MrR - ¿Puede ampliar "pero el problema exacto en el inserto no causó la actualización"?
Randall el
Cuando intenta utilizar insertar ... en la actualización en postgresql, los resultados son diferentes en algunas circunstancias específicas que una fusión. El caso con el que me topé fue bastante oscuro y específico, pero fue repetible. Han pasado unos meses, así que no puedo dar más ahora.
pojo-guy
¿Quizás no fue un conflicto sino otro error, por ejemplo, error de tipo de campo?
MrR