CodeGym /Corsi /SQL SELF /Gestione degli errori durante il caricamento dei dati ( ...

Gestione degli errori durante il caricamento dei dati ( ON CONFLICT)

SQL SELF
Livello 23 , Lezione 3
Disponibile

Benvenuto nel cuore dei drammi del caricamento massivo dei dati! Oggi impariamo a gestire in modo efficace gli errori che saltano fuori quando carichi dati, grazie alla clausola ON CONFLICT. È come mettere il pilota automatico sull’aereo: anche se qualcosa va storto, saprai cosa fare per evitare il disastro. Dai, vediamo insieme i trucchetti di PostgreSQL!

Nessuno ama le sorprese, soprattutto quando i dati si rifiutano di caricarsi! Nei processi di caricamento massivo puoi incontrare diversi problemi tipici:

  • Duplicazione dei dati. Per esempio, se nella tabella c’è una constraint UNIQUE e il tuo file dati è pieno di doppioni.
  • Conflitti con i vincoli. Tipo, provi a caricare un valore vuoto in una colonna con constraint NOT NULL. Risultato? Errore. PostgreSQL è sempre super rigido in queste situazioni.
  • Duplicazione della chiave primaria. La tabella potrebbe già avere dati con gli stessi identificatori che hai nel tuo file CSV.

Vediamo come evitare questi "scogli nascosti" con ON CONFLICT.

Uso di ON CONFLICT per gestire gli errori

La sintassi di ON CONFLICT ti permette di specificare cosa fare in caso di conflitto con i vincoli (tipo UNIQUE o PRIMARY KEY). PostgreSQL ti dà la possibilità di aggiornare i dati esistenti oppure ignorare la riga in conflitto.

Ecco come appare la sintassi base di ON CONFLICT:

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

Puoi sostituire DO UPDATE con DO NOTHING se vuoi semplicemente ignorare il conflitto.

Esempio: aggiornare i dati in caso di conflitto

Supponiamo di avere una tabella students:

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

Ora vogliamo caricare nuovi dati, ma alcuni sono già nel database:

INSERT INTO students (id, name, age)
VALUES 
    (1, 'Peter', 22),  -- Questo studente esiste già
    (2, 'Anna', 20),  -- Nuovo studente
    (3, 'Mal', 25) -- Nuovo studente
ON CONFLICT (id) DO UPDATE SET 
    name = EXCLUDED.name, 
    age = EXCLUDED.age;

In questo esempio, se esiste già uno studente con quell’ID che vuoi aggiungere, i suoi dati verranno aggiornati:

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

Nota la parola magica EXCLUDED. Significa "i valori che hai provato a inserire, ma sono stati esclusi a causa del conflitto".

Risultato:

  • Lo studente con id = 1 aggiornerà i suoi dati (nome e età).
  • Gli studenti con id = 2 e id = 3 verranno aggiunti alla tabella.

Esempio: ignorare i conflitti

Se non vuoi aggiornare i dati ma solo ignorare le righe che causano conflitto, usa DO NOTHING:

INSERT INTO students (id, name, age)
VALUES 
    (1, 'Peter', 22),  -- Questo studente esiste già
    (2, 'Anna', 20),  -- Nuovo studente
    (3, 'Mal', 25) -- Nuovo studente
ON CONFLICT (id) DO NOTHING;

Ora le righe in conflitto semplicemente non verranno inserite, e le altre si sistemeranno tranquille nel tuo database.

Log degli errori

A volte ignorare o aggiornare non basta. Per esempio, ti serve registrare i conflitti per analizzarli dopo. Possiamo creare una tabella speciale per loggare gli errori:

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

Poi aggiungiamo la gestione degli errori con logging:

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;

L’ultimo esempio funziona solo dentro le stored procedure. Come funziona esattamente lo vedrai quando studieremo PL-SQL. Sono andato un po’ avanti, ma volevo solo mostrarti un altro modo per gestire i conflitti nel caricamento dati: loggare tutte le righe problematiche.

Ora puoi analizzare le cause dei conflitti. Questa tecnica è super utile nei sistemi complessi, dove è importante tenere traccia di tutto durante i caricamenti massivi.

Esempio pratico

Mettiamo insieme tutto quello che abbiamo imparato in un esercizio semplice. Immagina di avere un file CSV con aggiornamenti degli studenti che vuoi caricare nella tabella:

File students_update.csv

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

Caricamento dati e gestione dei conflitti

  1. Prima creiamo una tabella temporanea tmp_students:
CREATE TEMP TABLE tmp_students (
  id   INTEGER,
  name TEXT,
  age  INTEGER
);
  1. Carichiamo i dati dal file usando \COPY:
\COPY tmp_students FROM 'students_update.csv' DELIMITER ',' CSV HEADER
  1. Inseriamo i dati dalla tabella temporanea in quella definitiva 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;

Ora tutti i dati, inclusi gli aggiornamenti (la riga con id = 1), sono stati caricati con successo.

Errori tipici e come evitarli

Gli errori capitano anche ai programmatori più esperti, ma se sai come evitarli puoi risparmiarti ore (o giorni!) di nervoso.

  • Conflitto con la constraint UNIQUE. Assicurati di aver indicato il campo giusto in ON CONFLICT. Per esempio, se metti la chiave sbagliata (id invece di email), PostgreSQL ti dirà semplicemente "ciao ciao" alla tua query.
  • Uso sbagliato di EXCLUDED. Questo alias si riferisce solo ai valori passati nella query corrente. Non provare a usarlo in altri contesti.
  • Colonne mancanti. Assicurati che tutte le colonne indicate in SET esistano nella tabella. Per esempio, se aggiungi SET non_existing_column = 'value', ti becchi un errore.

Usare ON CONFLICT rende il caricamento massivo dei dati in PostgreSQL flessibile e sicuro. Puoi non solo evitare che le query vadano in crash per i conflitti, ma anche controllare esattamente come gestire i tuoi dati. I tuoi utenti (e i server!) ti ringrazieranno.

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