2010-04-22 14 views
9

Così ho una tabella utenti in cui l'user.username ha molti duplicati come:caso duplicati insensibili SQL

username e Username e useRnAme
john e John e jOhn

Quello era un bug e questi tre i record avrebbero dovuto essere solo uno.

Sto cercando di trovare una query SQL che elenca tutti questi casi ordinati per data di creazione, così idealmente il risultato dovrebbe essere qualcosa di simile:

username jan01 
useRnAme jan02 
Username jan03 
john  feb01 
John  feb02 
jOhn  feb03 

Ogni suggerimento sarà molto apprezzato

+1

@hdx: La tua domanda è taggato 'mysql' e' postgresql'. Stai usando entrambi? –

+0

@hdx: memorizzi le date in quel formato e non in una colonna di date? –

+0

@Peter Lang, in effetti qualsiasi linguaggio sql dovrebbe fare, posso portarlo. Sto usando postgresql. – hdx

risposta

22

Lasciando da parte la questione della sensibilità caso per un momento, la strategia di base è:

SELECT username, create_date FROM your_table 
    WHERE username IN 
    (SELECT username FROM your_table GROUP BY username HAVING COUNT(*) > 1) 
ORDER BY username, create_date 

Molti RDBMS (tra cui MySQL supponendo che si sta utilizzando CHAR o VARCHAR per la colonna nome utente), eseguire case-insensitive ricerca per impostazione predefinita. Per quei database, la soluzione sopra funzionerà. Per risolvere il problema caso sensibilità per gli altri prodotti, avvolgere tutti tranne la prima occorrenza del nome utente nella funzione di conversione maiuscolo specifiche per il RDBMS:

SELECT username, create_date FROM your_table 
    WHERE UPPER(username) IN 
    (SELECT UPPER(username) FROM your_table GROUP BY UPPER(username) HAVING COUNT(*) > 1) 
ORDER BY username, create_date 
+0

Se è per MYSQL, UPPER non è necessario e potrebbe persino rendere la query inutilmente lenta. –

+0

Sì, è vero (e vero anche per vari altri RDBMS). Modificheremo la risposta per riflettere questo. –

+0

OK +1 per l'aggiornamento. –

0

Utilizzare ToLower() o funzione equivalente in SELECT e ordinare in base a tale colonna.

+0

Questo includerà nomi utente che non soffrono del problema di più ingressi. –

0

In MySQL, un confronto è fatto utilizzando un confronto binario tra maiuscole e minuscole. Così si potrebbe unire la tabella su se stessa, alla ricerca di righe in cui il caso confronto sensibile è diverso dal caso insensitive confrontare:

select * 
from YourTable t1 
inner join YourTable t2 
on t1.name <> t2.name collate latin1_bin 
and t1.name = t2.name 
1

provare qualcosa di simile questi

SELECT UserName, CreatedDate 
FROM User 
WHERE LOWER(TRIM(UserName)) IN 
(
SELECT LOWER(TRIM(UserName)) 
FROM User 
GROUP BY LOWER(TRIM(UserName)) 
HAVING count(*) > 1 
) 
+0

Opps, vedo che Larry ha pubblicato la stessa cosa prima –

0
SELECT UserName, CreatedDate 
FROM YourTable 
WHERE UserName COLLATE UTF8_BIN != LOWER(UserName COLLATE UTF8_BIN) 
GROUP BY UserName, CreatedDate 
HAVING COUNT(*) > 1 
+0

** Dalla coda di revisione **: Posso chiederti di aggiungere un po 'di contesto attorno al tuo codice sorgente. Le risposte al solo codice sono difficili da capire. Aiuterà il richiedente e i futuri lettori sia se puoi aggiungere ulteriori informazioni nel tuo post. – RBT