2013-08-15 3 views
6

Quindi sto provando a pulire alcuni record telefonici in una tabella di database.Il database di deduplicazione registra i valori confrontati in numerosi campi

ho trovato il modo di trovare corrispondenze esatte in 2 campi utilizzando:

/* DUPLICATE first & last names */ 

SELECT 
    `First Name`, 
    `Last Name`, 
    COUNT(*) c 
FROM phone.contacts 
GROUP BY 
    `Last Name`, 
    `First Name` 
HAVING c > 1; 

Wow, grande.

Desidero espandere ulteriormente per esaminare numerosi campi per vedere se un numero di telefono in 1 dei 3 campi del telefono è un duplicato.

Quindi voglio controllare 3 campi (general mobile, general phone, business phone).

1.per vedere che non sono vuoti ('') 2. per vedere se i dati (numero) in uno di essi appaiono negli altri 2 campi del telefono in qualsiasi punto della tabella.

Quindi, spingendo il mio SQL limitato oltre il limite, ho trovato il seguente che sembra restituire record con 3 campi di telefono vuoti & anche i record che non hanno numeri di telefono duplicati.

/* DUPLICATE general & business phone nos */ 

SELECT 
    id, 
    `first name`, 
    `last name`, 
    `general mobile`, 
    `general phone`, 
    `general email`, 
    `business phone`, 
    COUNT(CASE WHEN `general mobile` <> '' THEN 1 ELSE NULL END) as gen_mob, 
    COUNT(CASE WHEN `general phone` <> '' THEN 1 ELSE NULL END) as gen_phone, 
    COUNT(CASE WHEN `business phone` <> '' THEN 1 ELSE NULL END) as bus_phone 
FROM phone.contacts 
GROUP BY 
    `general mobile`, 
    `general phone`, 
    `business phone` 
HAVING gen_mob > 1 OR gen_phone > 1 OR bus_phone > 1; 

Chiaramente la mia logica è viziata & mi chiedevo se qualcuno mi potrebbe punto nella giusta direzione/pietà ecc ...

Molte grazie

+3

tag prega che DBMS si utilizza –

risposta

5

La prima cosa che dovresti fare è sparare alla persona che ha chiamato le tue colonne con spazi in esse.

Ebbene, provate questo:

SELECT DISTINCT 
    c.id, 
    c.`first name`, 
    c.`last name`, 
    c.`general mobile`, 
    c.`general phone`, 
    c.`business phone` 
from contacts_test c 
join contacts_test c2 
    on (c.`general mobile`!= '' and c.`general mobile` in (c2.`general phone`, c2.`business phone`)) 
    or (c.`general phone` != '' and c.`general phone` in (c2.`general mobile`, c2.`business phone`)) 
    or (c.`business phone`!= '' and c.`business phone` in (c2.`general mobile`, c2.`general phone`)) 

Consulta l'live demo di questa query in SQLFiddle.

Nota il controllo supplementare per phone != '', necessario perché i numeri di telefono non sono annullabili, quindi il loro valore "sconosciuto" è vuoto. Senza questo controllo, vengono restituite corrispondenze errate perché, ovviamente, lo spazio vuoto è vuoto.

La parola chiave DISTINCT è stata aggiunta nel caso in cui vi siano più altre righe corrispondenti, il che risulterebbe in un set di risultati nxn.

+0

Grazie per questo. Totalmente d'accordo sui nomi delle colonne. Immaginavo che il tuo script avrebbe semplicemente unito i record alla selezione che corrispondeva ai valori in generale telefono mobile, telefono generale e telefono aziendale, ma ciò che effettivamente accadeva era un ciclo infinito di record esattamente uguale alla selezione iniziale. Qualche idea? –

+0

Non capisco cosa intendi. Si prega di creare un [SQLFiddle] (http://www.sqlfiddle.com) compresi i dati per mostrare il problema – Bohemian

+0

Vedere [Dati SQLFiddle] (http://www.sqlfiddle.com/#!2/a3e29/6) Ok i dati di test hanno 3 record, 2 dei quali contengono un numero duplicato. Corro il codice sopra e restituisce 9 righe. Presumibilmente la dichiarazione di join non sta controllando che ci sia una corrispondenza prima di unire i record Grazie in anticipo –

0

Si può provare qualcosa di simile:

SELECT * from phone.contacts p WHERE `general mobile` IN (SELECT `general mobile` FROM phone.contacts WHERE id != p.id UNION SELECT `general phone` FROM phone.contacts WHERE id != p.id UNION SELECT `general email` FROM phone.contacts WHERE id != p.id) 

Ripetere 3 volte per ciascuna: general mobile, general phone e general email. Può essere inserito in una singola query ma sarebbe meno leggibile.

1

Nella mia esperienza, quando si puliscono i dati, è molto meglio avere una visione comprensiva dei dati, e un modo semplice per gestirli, piuttosto che avere una query grande e voluminosa che faccia tutte le analisi contemporaneamente.

È anche possibile, (più o meno) rinormalizzare il database, utilizzando qualcosa di simile:

Create view VContactsWithPhones 
as 
Select id, 
     `Last Name` as LastName, 
     `First Name` as FirstName, 
     `General Mobile` as Phone, 
     'General Mobile' as PhoneType 
From phone.contacts c 
UNION 
Select id, 
     `Last Name`, 
     `First Name`, 
     `General Phone`, 
     'General Phone' 
From phone.contacts c 
UNION 
Select id, 
     `Last Name`, 
     `First Name`, 
     `Business Phone`, 
     'Business Phone' 
From phone.contacts c 

Questo genererà una vista con tripla le righe della tabella originale, ma con una colonna Phone, che può essere di uno dei tre tipi.

È possibile di selezionare facilmente da questo punto di vista:

//empty phones 
SELECT * 
FROM VContactsWithPhones 
Where Phone is null or Phone = '' 

//duplicate phones 
Select Phone, Count(*) 
from VContactsWithPhones 
where (Phone is not null and Phone <> '') -- exclude empty values 
group by Phone 
having count(*) > 1 

//duplicate phones belonging to the same ID (double entries) 
Select Phone, ID, Count(*) 
from VContactsWithPhones 
where (Phone is not null and Phone <> '') -- exclude empty values 
group by Phone, ID 
having count(*) > 1 

//duplicate phones belonging to the different ID (duplicate entries) 
Select v1.Phone, v1.ID, v1.PhoneType, v2.ID, v2.PhoneType 
from VContactsWithPhones v1 
    inner join VContactsWithPhones v2 
    on v1.Phone=v2.Phone and v1.ID=v2.ID 
where v1.Phone is not null and v1.Phone <> '' 

ecc, ecc ...

Problemi correlati