If I'm inserting records, it's really easy to query to see if another record already exists with the same values in a before trigger. Code like this has worked for me:

private static Map<String, List<Account>> getPotentialMatches() {
   Map<String, List<Account>> potentialMatches = new Map<String, List<Account>>();

   for(Account a : [SELECT FirstName, LastName, PersonMailingStreet, PersonMailingCity, PersonMailingState, PersonMailingPostalCode
                    FROM Account 
                    WHERE IsPersonAccount = true
                    AND FirstName IN :firstNames
                    AND LastName IN :lastNames
                    AND PersonMailingStreet IN :streets
                    AND PersonMailingCity IN :cities
                    AND PersonMailingState IN :states
                    AND PersonMailingPostalCode IN :postalCodes])
      String key = (a.FirstName + 
                    a.LastName + 
                    a.PersonMailingStreet + 
                    a.PersonMailingCity + 
                    a.PersonMailingState + 

      if(potentialMatches.containsKey(k)) {
      } else {
         potentialMatches.put(k, new List<Account>{a});

   return potentialMatches;

Code appears to work well for exact matching. Where I think it lacks is matching against fuzzy logic.

enter image description here

From what I can tell from the docs, Salesforce has some of their own algorithms to deal with fuzzy matching (e.g. Main St vs Main Street vs Main Rd, etc). In addition, what makes matching rules nice is an admin can easily tweak them via config.

Besides the fuzzy algorithm matching and admin friendly config, what other benefits are there with using config matching/duplication vs code?

The reason I'm asking, I have a requirement that is using 20+ fields on the object and complex conditions (e.g. A && B && (C || D) && ( E || F) && (G || H) && I) to determine if a record already exists in the org. There are 8 different combinations of these complex conditions.

There are limits to using config. You can only have 3 matching rules per object. For the matching criteria in the config rules, you can only pick 10 fields. It's making sense for me to use code for exact matching rules, and config for the fuzzy matching.


Your code has a pretty significant flaw, FYI: It's possible match records incorrectly. Do not use a simple string, there's a small chance you might get in to a situation where records match incorrectly (e.g. "Joh nDoe" vs "John Doe"). The chance is exceedingly small, but you actually easily avoid this by using a sObject key:

Map<Account, List<Account>> potentialMatches = new Map<Account, List<Account>>();


Account key = new Account(FirstName=a.FirstName?.toLowerCase(),

Apparently the limits are five matching rules per object, not three. I'm not sure if this changes your design choices, but it's worth double-checking.

Using code-based matching means that you miss out on some standard features, like the Potential Duplicates section of the record layout. You have to either make your own UI for it, or whatever it is you're doing.

There's a list of features you can request increases for, but the Duplicate Rule limits aren't listed, but you might still try to enable a feature or limit that is not listed.

  • thanks for sharing about the sobject key. can any object be used as a key even one create from a custom class? – Tyler Zika May 3 at 15:57
  • @TylerZika for custom classes, you must implement equals() and hashCode(), as mentioned in the docs linked. Not all standard classes can be used as a key, like QueryLocator, for example, but almost any class you'd want to use, like Date or Integer, can be used. – sfdcfox May 3 at 16:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.