CodeGym /Cursos /SQL SELF /Manejo de errores al cargar datos ( ON CONFLICT

Manejo de errores al cargar datos ( ON CONFLICT)

SQL SELF
Nivel 23 , Lección 3
Disponible

¡Bienvenido al corazón de los escenarios dramáticos de carga masiva de datos! Hoy vamos a aprender a manejar de forma eficiente los errores que aparecen al cargar datos usando la construcción ON CONFLICT. Es como poner el piloto automático en un avión: aunque algo salga mal, sabrás qué hacer para evitar una catástrofe. ¡Vamos a descubrir los trucos de PostgreSQL!

¡A nadie le gustan las sorpresas, sobre todo cuando los datos se niegan a cargarse! En los procesos de carga masiva puedes encontrarte con varios problemas típicos:

  • Duplicación de datos. Por ejemplo, si la tabla tiene una restricción UNIQUE y tu archivo de datos está lleno de repeticiones.
  • Conflictos con restricciones. Por ejemplo, intenta cargar un valor vacío en una columna con restricción NOT NULL. ¿El resultado? Error. PostgreSQL siempre es muy estricto en estas situaciones.
  • Información primaria duplicada. La tabla puede que ya tenga datos con los mismos identificadores que tu archivo CSV.

Vamos a ver cómo evitar estos "icebergs" usando ON CONFLICT.

Uso de ON CONFLICT para manejar errores

La sintaxis de ON CONFLICT te permite indicar qué hacer si hay un conflicto con las restricciones (por ejemplo, UNIQUE o PRIMARY KEY). PostgreSQL te da la opción de actualizar los datos existentes o simplemente ignorar la fila en conflicto.

Así se ve la sintaxis básica de ON CONFLICT:

INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...)
ON CONFLICT (conflict_target)
DO UPDATE SET column1 = new_value1, column2 = new_value2;

Puedes cambiar DO UPDATE por DO NOTHING si solo quieres ignorar el conflicto.

Ejemplo: actualizar datos en caso de conflicto

Supón que tienes una tabla students:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    age INT
);

Ahora queremos cargar nuevos datos, pero algunos ya existen en la base:

INSERT INTO students (id, name, age)
VALUES 
    (1, 'Peter', 22),  -- Este estudiante ya existe
    (2, 'Anna', 20),  -- Nuevo estudiante
    (3, 'Mal', 25) -- Nuevo estudiante
ON CONFLICT (id) DO UPDATE SET 
    name = EXCLUDED.name, 
    age = EXCLUDED.age;

En este ejemplo, si ya existe un estudiante con el ID que queremos añadir, sus datos serán actualizados:

ON CONFLICT (id) DO UPDATE SET
    name = EXCLUDED.name, 
    age = EXCLUDED.age;

Fíjate en la palabra mágica EXCLUDED. Significa "los valores que intentaste insertar pero fueron excluidos por el conflicto".

Resultado:

  • El estudiante con id = 1 actualizará sus datos (nombre y edad).
  • Los estudiantes con id = 2 y id = 3 serán añadidos a la tabla.

Ejemplo: ignorar conflictos

Si no quieres actualizar datos, sino solo ignorar las filas que causan conflicto, usa DO NOTHING:

INSERT INTO students (id, name, age)
VALUES 
    (1, 'Peter', 22),  -- Este estudiante ya existe
    (2, 'Anna', 20),  -- Nuevo estudiante
    (3, 'Mal', 25) -- Nuevo estudiante
ON CONFLICT (id) DO NOTHING;

Ahora las filas en conflicto simplemente no se insertarán, y las demás entrarán tranquilamente en tu base.

Registro de errores

A veces ignorar o actualizar no es suficiente. Por ejemplo, necesitas registrar los conflictos para analizarlos después. Podemos crear una tabla especial para registrar errores:

CREATE TABLE conflict_log (
    conflict_time TIMESTAMP DEFAULT NOW(),
    id INT,
    name TEXT,
    age INT,
    conflict_reason TEXT
);

Luego añadimos el manejo de errores con registro:

INSERT INTO students (id, name, age)
VALUES 
    (1, 'Peter', 22), 
    (2, 'Anna', 20), 
    (3, 'Mal', 25)
ON CONFLICT (id) DO UPDATE SET 
    name = EXCLUDED.name, 
    age = EXCLUDED.age
RETURNING EXCLUDED.id, EXCLUDED.name, EXCLUDED.age
INTO conflict_log;

Este último ejemplo solo funcionará dentro de procedimientos almacenados. Cómo funciona exactamente lo verás cuando estudiemos PL-SQL. Me adelanté un poco, solo quería mostrarte otra forma de resolver conflictos al cargar datos: registrar todas las filas problemáticas.

Ahora puedes analizar las razones de los conflictos. Esta técnica es especialmente útil en sistemas complejos donde es importante guardar "rastros" durante cargas masivas de datos.

Ejemplo práctico

Vamos a juntar todo lo aprendido en una tarea sencilla. Imagina que tienes un archivo CSV con actualizaciones de estudiantes que quieres cargar en la tabla:

Archivo students_update.csv

id name age
1 Otto 23
2 Anna 21
4 Wally 30

Carga de datos y manejo de conflictos

  1. Primero creamos una tabla temporal tmp_students:
CREATE TEMP TABLE tmp_students (
  id   INTEGER,
  name TEXT,
  age  INTEGER
);
  1. Cargamos los datos del archivo usando \COPY:
\COPY tmp_students FROM 'students_update.csv' DELIMITER ',' CSV HEADER
  1. Insertamos los datos de la tabla temporal en la permanente usando INSERT ON CONFLICT:
INSERT INTO students (id, name, age)
SELECT id, name, age FROM tmp_students
ON CONFLICT (id) DO UPDATE
  SET name = EXCLUDED.name,
      age = EXCLUDED.age;

Ahora todos los datos, incluidas las actualizaciones (la fila con id = 1), se han cargado correctamente.

Errores típicos y cómo evitarlos

Los errores pasan incluso a los programadores más experimentados, pero si sabes cómo evitarlos, te ahorrarás horas (¡o incluso días!) de nervios.

  • Conflicto con la restricción UNIQUE. Asegúrate de indicar el campo correcto en ON CONFLICT. Por ejemplo, si pones la clave equivocada (id en vez de email), PostgreSQL simplemente le dirá "adiós" a tu consulta.
  • Uso incorrecto de EXCLUDED. Este alias solo se refiere a los valores pasados en la consulta actual. No intentes usarlo en otros contextos.
  • Omisión de columnas. Asegúrate de que todas las columnas indicadas en SET existen en la tabla. Por ejemplo, si añades SET non_existing_column = 'value', tendrás un error.

Usar ON CONFLICT hace que la carga masiva de datos en PostgreSQL sea flexible y segura. No solo puedes evitar que tus consultas fallen por conflictos, sino que también controlas cómo se manejan tus datos. Tus usuarios (¡y tus servidores!) te lo agradecerán.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION