2013-08-15 7 views
6

Ich versuche also, einige Telefoneinträge in einer Datenbanktabelle zu bereinigen.Deduplizieren von Datenbankaufzeichnungen Vergleichen von Werten in zahlreichen Feldern

Ich habe herausgefunden, wie mit genauen Treffer in 2 Bereichen zu finden:

/* DUPLICATE first & last names */ 

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

Wow, großartig.

Ich möchte es weiter zu sehen, um zahlreiche Felder zu sehen, ob eine Telefonnummer in 1 von 3 Telefonfeldern ein Duplikat ist.

Also ich möchte 3 Felder überprüfen (general mobile, general phone, business phone).

1.zu sehen, dass sie nicht leer sind ('') 2. um zu sehen, ob die Daten (Nummer) in einem von ihnen in den anderen 2 Telefonfeldern irgendwo in der Tabelle erscheint.

Also drückte ich meine begrenzte SQL über ihre Grenze Ich kam mit der folgenden, die Datensätze mit 3 leeren Telefonfelder & Datensätze auch, die keine doppelte Telefonnummern haben scheint.

/* 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; 

klar meine Logik ist fehlerhaft & Ich fragte mich, ob jemand mich in die richtige Richtung zeigen könnte/erbarme etc ...

Vielen Dank

+3

bitte Tag, das DBMS sind Sie –

Antwort

5

Das erste, was Sie tun sollten, schießen Sie die Person, die Ihre Spalten mit Leerzeichen in ihnen benannt.

Nun, versuchen Sie dies:

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`)) 

eine live demo dieser Abfrage in SQLFiddle See.

Beachten Sie die zusätzliche Überprüfung für phone != '', die erforderlich ist, da die Telefonnummern nicht nullfähig sind, so dass ihr Wert "unbekannt" leer ist. Ohne diese Prüfung werden falsche Übereinstimmungen zurückgegeben, da natürlich leer gleich leer ist.

Das Schlüsselwort DISTINCT wurde hinzugefügt, falls mehrere andere übereinstimmende Zeilen vorhanden sind, was zu einer nxn-Ergebnismenge führen würde.

+0

Vielen Dank für das verwenden. Stimmen Sie völlig über die Spaltennamen überein. Ich nahm an, dass Ihr Skript einfach Datensätze mit der Auswahl verbinden würde, die den Werten in allgemeinem Mobiltelefon, allgemeinem Telefon und geschäftlichem Telefon entsprechen, aber was wirklich geschah, war eine endlose Schleife von Aufzeichnungen genau die selbe wie die anfängliche Auswahl. Irgendwelche Ideen? –

+0

Ich verstehe nicht, was du meinst. Bitte erstellen Sie eine [SQLFiddle] (http://www.sqlfiddle.com) einschließlich Daten, um das Problem zu zeigen – Bohemian

+0

Siehe [SQLFiddle Daten] (http://www.sqlfiddle.com/#!2/a3e29/6) Ok so Die Testdaten haben 3 Datensätze, von denen 2 eine doppelte Nummer enthalten. Ich führe den obigen Code & es gibt 9 Zeilen zurück. Vermutlich prüft die Join-Anweisung nicht, dass es eine Übereinstimmung gibt, bevor Datensätze hinzugefügt werden Vielen Dank im Voraus –

0

können Sie versuchen, so etwas wie:

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) 

Wiederholen Sie dreimal für jede: general mobile, general phone und general email. Es kann in eine einzelne Abfrage gestellt werden, wäre aber weniger lesbar.

1

Nach meiner Erfahrung ist es bei der Bereinigung von Daten viel besser, eine verständliche Ansicht der Daten und eine einfache Verwaltung zu haben, als eine große und sperrige Abfrage zu haben, die alle Analysen gleichzeitig durchführt.

Sie können auch (mehr oder weniger) renormieren die Datenbank, wie etwas mit:

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 

Dies wird eine Ansicht mit triple den Reihen der ursprünglichen Tabelle erzeugen, aber mit einer Phone Säule, das kann von einem von drei Arten sein.

können Sie als leicht wählen Sie aus dieser Ansicht:

//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 <> '' 

etc, etc ...