Fuzzy Name Matching With SOUNDEX and DIFFERENCE

Fuzzy name matching with SOUNDEX and DIFFERENCE finds names that sound alike, not customers who are the same person. Treat every hit as a question for a human, never as an answer.

Similar maracas with different seeds visible through their open plugs

The duplicate customers nobody can find

Your sales team says the customer list has duplicates. “Smith” and “Smyth” at the same address, probably typed by two different people. An exact match will never find them, because the spellings differ.

SQL Server has two old but handy functions for this. SOUNDEX turns a name into a four-character sound code. DIFFERENCE compares two sound codes and returns a score from 0 to 4, where 4 means the most alike.

Let me build a small customer list. Two postal codes, four names. The query shows the sound code for each name.

DROP TABLE IF EXISTS #NameCandidates;

CREATE TABLE #NameCandidates (
    Id         int PRIMARY KEY,
    Name       nvarchar(60),
    PostalCode varchar(12));

INSERT #NameCandidates VALUES
    (1, N'Smith', '10001'), (2, N'Smyth', '10001'),
    (3, N'Lee',   '10002'), (4, N'Li',    '10002');

SELECT Id, Name, SOUNDEX(Name) AS PhoneticCode
FROM #NameCandidates
ORDER BY Id;

Smith and Smyth share the code S530. Lee and Li share L000. That is the whole trick. Names that sound alike get the same code.

Score the pairs inside a block

Now compare names pairwise. Two details matter here. The join requires the second Id to be greater than the first, so each pair appears once. And it only compares names inside the same postal code, which I call a block.

SELECT a.Id AS FirstId, b.Id AS SecondId,
       a.Name AS FirstName, b.Name AS SecondName,
       DIFFERENCE(a.Name, b.Name) AS PhoneticScore
FROM #NameCandidates AS a
JOIN #NameCandidates AS b
  ON b.PostalCode = a.PostalCode AND b.Id > a.Id
WHERE DIFFERENCE(a.Name, b.Name) >= 3
ORDER BY PhoneticScore DESC, a.Id, b.Id;

SELECT SOUNDEX(N'Li') AS LiCode, SOUNDEX(N'Lo') AS LoCode,
       DIFFERENCE(N'Li', N'Lo') AS DifferentNamesScore;

SELECT SOUNDEX(CONVERT(nvarchar(20), NULL)) AS NullCode,
       DIFFERENCE(N'Smith', CONVERT(nvarchar(20), NULL)) AS NullScore;
SQL Server results showing phonetic candidate pairs and matching Li and Lo codes
The sound codes, the two candidate pairs, Li and Lo with the same code, and the NULL result.

The second grid has two candidates: Smith with Smyth, and Lee with Li. Both score 4. Smith and Smyth look like a real duplicate. Lee and Li might be two different people.

The third grid proves the point. Li and Lo are clearly different names, yet they have the same code and score 4. The last grid shows a NULL name gives a NULL code and a NULL score. Missing data never matches anything.

Where the scale fools you

The score has only five levels, and the cutoff is a guess. Look at a few pairs side by side.

SELECT a AS NameA, b AS NameB, SOUNDEX(a) AS CodeA, SOUNDEX(b) AS CodeB,
       DIFFERENCE(a, b) AS Score
FROM (VALUES (N'Smith', N'Smythe'), (N'Smith', N'Jones'),
             (N'Catherine', N'Katherine'), (N'Robert', N'Rupert')) AS v (a, b)
ORDER BY Score DESC, a;

Smith and Jones score 2, which is low but not zero. Catherine and Katherine score only 3, because SOUNDEX keeps the first letter, and C is not K. A cutoff of 4 would miss them. A cutoff of 3 catches them and lets in more noise. Test your own cutoff against names you already know are matches and non-matches.

Why I compare inside a block

Comparing every name with every other name explodes fast. Count the pairs.

SELECT COUNT(*) AS AllPairs,
       SUM(CASE WHEN a.PostalCode = b.PostalCode THEN 1 ELSE 0 END) AS SamePostalCodePairs
FROM #NameCandidates AS a
JOIN #NameCandidates AS b ON b.Id > a.Id;

SELECT CAST(100000 AS bigint) * 99999 / 2 AS PairsFor100000Customers;

Four names make 6 pairs, and only 2 share a postal code. For 100,000 customers the count is 4,999,950,000. Blocking cuts that to something you can run. The price is that a customer who moved will never be compared with their old record, so pick a block that fits your review process.

From sound codes to a human decision

Suggestion, not identity

SOUNDEX was built around English names and is weak elsewhere. Keep the candidate ids, the blocking rule, the score and the human decision. Add evidence like an exact address or a customer number. And never overwrite a name just to improve a score.

DROP TABLE IF EXISTS #NameCandidates;

Let the score shorten the review list, then let a person decide.

A phonetic match is not an identity match, it is a candidate to inspect.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.


Discover more from SQL Authority with Pinal Dave

Subscribe to get the latest posts sent to your email.

SQL Function, SQL Scripts, SQL Server
Previous Post
SQL SERVER – Configuring Interactive Cleansing Suggestion Min Score for Suggestions in Data Quality Services (DQS) – Sensitivity of Suggestion
Next Post
SQL SERVER – Why Do We Need Master Data Management – Importance and Significance of Master Data Management (MDM)

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.