Ecco sette modi per restituire righe duplicate in MariaDB quando tali righe hanno una chiave primaria o un'altra colonna di identificatore univoco.
Pertanto, le righe duplicate condividono esattamente gli stessi valori in tutte le colonne ad eccezione della colonna dell'identificatore univoco.
Dati di esempio
Utilizzeremo i seguenti dati per i nostri esempi:
SELECT * FROM Dogs;
Risultato:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Le prime due righe sono duplicate (tranne per DogId
colonna, che è la chiave primaria della tabella e contiene un valore univoco in tutte le righe). Anche le ultime tre righe sono duplicate (ad eccezione di DogId
colonna).
La colonna della chiave primaria assicura che non vi siano righe duplicate, il che normalmente è positivo negli RDBMS. Tuttavia, per definizione questo significa che non ci sono duplicati. Nel nostro caso, la colonna della chiave primaria è un numero incrementale e il suo valore non ha significato e non è significativo. Dobbiamo quindi ignorare quella riga se vogliamo trovare duplicati nelle colonne che sono significativo.
Opzione 1
Possiamo usare il GROUP BY
clausola per raggruppare le colonne in base alle colonne significative, quindi utilizzare il COUNT()
funzione per restituire il numero di righe identiche:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Risultato:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Ruff | Robinson | 1 | | Wag | Johnson | 3 | | Woof | Jones | 1 | +-----------+----------+-------+
Siamo stati in grado di escludere la colonna della chiave primaria omettendola dalla nostra query.
Il risultato ci dice che ci sono due righe contenenti Bark Smith e tre righe contenenti Wag Johnson. Questi sono duplicati (o triplicati nel caso di Wag Johnson). Le altre due righe non hanno duplicati.
Opzione 2
Possiamo escludere i non duplicati dall'output con HAVING
clausola:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Risultato:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Wag | Johnson | 3 | +-----------+----------+-------+
Opzione 3
È anche possibile verificare la presenza di duplicati su colonne concatenate. Ad esempio, possiamo usare CONCAT()
per concatenare le nostre due colonne, usa il DISTINCT
parola chiave per ottenere valori distinti, quindi utilizzare COUNT()
funzione per restituire il conteggio:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Risultato:
+---------------+-------+ | DogName | Count | +---------------+-------+ | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+-------+
Opzione 4
Possiamo usare il ROW_NUMBER()
funzione con il PARTITION BY
clausola:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Risultato:
+-------+-----------+----------+------------+ | DogId | FirstName | LastName | Row_Number | +-------+-----------+----------+------------+ | 1 | Bark | Smith | 1 | | 2 | Bark | Smith | 2 | | 4 | Ruff | Robinson | 1 | | 6 | Wag | Johnson | 1 | | 5 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | | 3 | Woof | Jones | 1 | +-------+-----------+----------+------------+
In questo modo viene creata una nuova colonna con un numero di riga che aumenta ogni volta che è presente un duplicato, ma viene reimpostato di nuovo quando è presente una riga univoca.
In questo caso non stiamo raggruppando i risultati, il che significa che possiamo vedere ogni riga duplicata, inclusa la relativa colonna dell'identificatore univoco.
Opzione 5
Possiamo anche utilizzare l'esempio precedente come espressione di tabella comune in una query più ampia:
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs
)
SELECT * FROM cte WHERE Row_Number <> 1;
Risultato:
+-------+-----------+----------+------------+ | DogId | FirstName | LastName | Row_Number | +-------+-----------+----------+------------+ | 2 | Bark | Smith | 2 | | 5 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +-------+-----------+----------+------------+
Ciò esclude i non duplicati dall'output ed esclude una riga di ogni duplicato dall'output.
Questa query potrebbe essere utilizzata come precursore di un'operazione di deduplicazione. Può mostrarci cosa verrà eliminato se decidiamo di eliminare i duplicati. Per deduplicare la tabella, tutto ciò che dobbiamo fare è sostituire l'ultimo SELECT *
con DELETE
.
Opzione 6
Ecco un modo più conciso per ottenere lo stesso output dell'esempio precedente:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Risultato:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Questo esempio non richiede la generazione del nostro numero di riga separato.
Possiamo sostituire SELECT *
con DELETE
per eliminare i duplicati.
Opzione 7
E infine, ecco un'altra opzione per restituire i duplicati:
SELECT *
FROM Dogs d1, Dogs d2
WHERE d1.FirstName = d2.FirstName
AND d1.LastName = d2.LastName
AND d1.DogId <> d2.DogId
AND d1.DogId = (
SELECT MAX(DogId)
FROM Dogs d3
WHERE d3.FirstName = d1.FirstName
AND d3.LastName = d1.LastName
);
Risultato:
+-------+-----------+----------+-------+-----------+----------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | +-------+-----------+----------+-------+-----------+----------+ | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +-------+-----------+----------+-------+-----------+----------+