Sappiamo bene che nella costruzione dei databases relazionali è fondamentale mantenere l'integrità delle entità. Per questo motivo le tabelle di SQL Server non devono contenere record duplicati o chiavi primarie non uniche. SQL Server possiede a tale scopo vari meccanismi per rinfonzare l'integrità delle entità: indici univoci, vincoli UNIQUE e PRIMARY KEY (d'ora in poi PK) ed infine i TRIGGER.
Ovviamente in alcune situazioni questi meccanismi non sono immediatamente
attuabili, ad esempio quando importiamo dati da fonti esterne all'interno di tabelle di SQL Server. In questi casi è fondamentali fare una analisi sui dati importati per identificare una chiave candidata a diventare PK. Per definizione la PK di una tabella è unica all'interno della stessa, quindi dobbiamo accertarci che non vi siano nella tabella valori duplicati per le colonne candidate ad essere chiave primaria.
Per fare questo dobbiamo identificare i record duplicati,
eliminarli ed inserire i valori univoci corrispondenti nella
tabella originale.
Un esempio pratico
Creiamo allo scopo una tabella in cui la chiave candidata a diventare PK sia
composta da due colonne (col1,col2) ed inseriamo dei dati appositamente combinati per avere record duplicati sulla chiave candidata a PK.
create table tabella_demo(col1 int, col2 int, col3 char(50))
insert into tabella_demo values (1, 1, 'prima serie dati')
insert into tabella_demo values (1, 1, 'prima serie dati')
insert into tabella_demo values (1, 1, 'prima serie dati')
insert into tabella_demo values (1, 2, 'seconda serie dati')
insert into tabella_demo values (1, 3, 'terza serie dati')
insert into tabella_demo values (1, 4, 'quarta serie dati')
insert into tabella_demo values (1, 5, 'quinta serie dati')
insert into tabella_demo values (1, 6, 'sesta serie dati')
insert into tabella_demo values (1, 6, 'sesta serie dati')
Ora se proviamo a creare un indice univoco uni_tabella_demo nella tabella e sulle colonne col1 e col2:
CREATE UNIQUE INDEX uni_tabella_demo ON tabella_demo (col1,col2)
Dovremmo ricevere un messaggio di errore da SQL Server:
Server: Msg 1505, Level 16, State 1, Line 1
CREATE UNIQUE INDEX terminated because a duplicate key was found for index ID
2. Most significant primary key is '1'.
The statement has been terminated.
L'errore è piuttosto chiaro, SQL Server dice che non può creare
l'indice uni_tabella_demo sulla tabella tabella_demo perché esistono valori duplicati per la chiave primaria indicata (le col1 e col2).
Ora è necessario trovare i valori duplicati nella tabella, per fare
ciò usiamo questa query:
SELECT col1, col2, count(*) AS conteggio
FROM tabella_demo
GROUP BY col1, col2
HAVING count(*) > 1
Il risultato della query mostra i singoli valori delle chiavi primarie duplicate e nella colonna conteggio il numero dei duplicati di queste.
Col1 |
Col2 |
|
1 |
1 |
3 |
1 |
6 |
2 |
È evidente che dobbiamo eliminare questi duplicati se vogliamo che la chiave primaria composta dalle colonne col1 e col2 sia univoca all'interno della tabella tabella_demo.
Primo step, mettere al sicuro i valori univoci delle chiavi duplicate all'interno della tabella chiavidup
SELECT col1, col2, col3=count(*)
INTO chiavidup
FROM tabella_demo
GROUP BY col1, col2
HAVING count(*) > 1
Secondo step, mettere al sicuro le singole righe duplicate all'interno della
tabella valoridup
SELECT DISTINCT tabella_demo.*
INTO valoridup
FROM tabella_demo, chiavidup
WHERE tabella_demo.col1 = chiavidup.col1
AND tabella_demo.col2 = chiavidup.col2
Ora la tabella valoridup dovrebbe contenere i valori unici per ogni chiave candidata, verifichiamolo con questa query:
SELECT col1, col2, count(*) as conteggio
FROM valoridup
GROUP BY col1, col2
Se il valore nella colonna conteggio è uguale a 1 per ogni riga della tabella valoridup solo allora possiamo procedere ad eliminare i record duplicati dalla tabella originale tabella_demo.
DELETE tabella_demo
FROM tabella_demo, chiavidup
WHERE tabella_demo.col1 = chiavidup.col1
AND tabella_demo.col2 = chiavidup.col2
Ed ora dopo aver eliminato i valori duplicati delle chiavi primarie dalla
tabella originale, inseriamo i valori univoci precedentemente salvati in valoridup:
INSERT tabella_demo SELECT * FROM valoridup
Ora controllate i valori della tabella tabella_demo e vi renderete conto che effettivamente i valori delle colonne col1 e col2 sono univoci e quindi queste colonne sono una chiave primaria valida!
SELECT * FROM tabella_demo ORDER BY col1, col2
Per avere una maggiore conferma proviamo ora a creare l'indice univoco (equivalente alla chiave primaria) visto precedentemente sulla tabella tabella_demo:
CREATE UNIQUE INDEX uni_tabella_demo ON tabella_demo (col1,col2)
Nessun errore! SQL Server ha creato correttamente l'indice sulla tabella.