Merging Records

When you have duplicate lead, contact, case, or account records in the database, cleaning up your data and consolidating the records is a good idea. You can merge up to three records of the same sObject type. The merge operation merges the duplicate records into the main record, deletes the duplicate records, and reparents any related records.

Use the merge Statement

This example shows how to merge a duplicate account record into a main account record. The duplicate account has a related contact, which is moved to the main account record after the merge operation. After merging, the duplicate record is deleted and only the main record remains in the database.

1// Insert new accounts
2List<Account> ls = new List<Account>{
3    new Account(Name = 'Acme Inc.'),
4    new Account(Name = 'Acme')
5};                                        
6insert as user ls;
7
8// Queries to get the inserted accounts 
9Account mainAcct = [
10    SELECT Id, Name 
11    FROM Account 
12    WHERE Name = 'Acme Inc.' 
13    WITH USER_MODE 
14    LIMIT 1
15];
16
17Account dupAcct = [
18    SELECT Id, Name 
19    FROM Account 
20    WHERE Name = 'Acme' 
21    WITH USER_MODE 
22    LIMIT 1
23];
24
25// Add a contact to the account to be merged
26Contact c = new Contact(FirstName = 'Joe', LastName = 'Merged');
27c.AccountId = dupAcct.Id;
28insert as user c;
29
30try {
31    merge mainAcct dupAcct;
32} catch (DmlException e) {
33    // Process exception
34    System.debug('An unexpected error has occurred: ' + e.getMessage()); 
35}
36
37// After the account is merged with the main account,
38// the related contact is moved to the main record.
39mainAcct = [
40    SELECT Id, Name, (SELECT FirstName, LastName FROM Contacts) 
41    FROM Account 
42    WHERE Name = 'Acme Inc.'  
43    WITH USER_MODE 
44    LIMIT 1
45];
46
47Assert.isTrue(mainAcct.getSObjects('Contacts').size() > 0);
48Assert.areEqual('Joe', mainAcct.getSObjects('Contacts')[0].get('FirstName'));
49Assert.areEqual('Merged', mainAcct.getSObjects('Contacts')[0].get('LastName'));
50
51// Verify that the duplicate record is deleted
52Account[] result = [SELECT Id, Name FROM Account WHERE Id = :dupAcct.Id WITH USER_MODE];
53Assert.areEqual(0, result.size());

Use the Database.merge Method

This second example is similar to the previous example, except that it uses the Database.merge method instead of the merge statement. The last argument of Database.merge is set to false, so any errors encountered in this operation are returned in the merge result without throwing exceptions. In the example, a main account and two duplicate account records are created. One of the duplicate account records has a child contact record. Through the merge operation, the contact is moved to the main account record, and the other records are deleted.

To use the AccountContactRelation sObject in this example, enable the “Allow users to relate a contact to multiple accounts” setting in your org. See Set Up Contacts to Multiple Accounts.

Note

1// Create main account
2Account main = new Account(Name = 'Account1');
3insert as user main;
4
5// Create duplicate accounts
6List<Account> duplicates = new List<Account>{
7    // Duplicate account 
8    new Account(Name = 'Account1, Inc.'),
9    // Second duplicate account
10    new Account(Name = 'Account 1')
11};
12insert as user duplicates;
13
14// Create child contact and associate it with first account
15Contact c = new Contact(FirstName = 'Joe', LastName = 'Smith', AccountId = duplicates[0].Id);
16insert as user c;
17
18// Get the account contact relation ID, which is created when a contact is created on "Account1, Inc." 
19AccountContactRelation resultAcrel = [
20    SELECT Id 
21    FROM AccountContactRelation 
22    WHERE ContactId = :c.Id 
23    WITH USER_MODE 
24    LIMIT 1
25];
26
27// Merge duplicate accounts into main account
28Database.MergeResult[] results = Database.merge(main, duplicates, false);
29
30for (Database.MergeResult res : results) {
31    if (res.isSuccess()) {
32        // Get the main record ID from the result and validate it
33        System.debug('Main record ID: ' + res.getId());
34        Assert.areEqual(main.Id, res.getId());              
35        
36        // Get the IDs of the merged records and display them
37        List<Id> mergedIds = res.getMergedRecordIds();
38        System.debug('IDs of merged records: ' + mergedIds);                
39        
40        // Get the ID of the reparented record and validate that this is the contact ID.
41        System.debug('Reparented record ID: ' + res.getUpdatedRelatedIds());
42
43        // Make sure there are two IDs (contact ID and account contact relation ID); the order isn't defined
44        Assert.areEqual(2, res.getUpdatedRelatedIds().size());    
45        Boolean flag1 = false;
46        Boolean flag2 = false;
47
48        // Because the order of the IDs isn't defined, the ID can be at index 0 or 1 of the array         
49        if (resultAcrel.Id == res.getUpdatedRelatedIds()[0] || resultAcrel.Id == res.getUpdatedRelatedIds()[1]) {
50            flag1 = true;
51        }
52        
53        if (c.Id == res.getUpdatedRelatedIds()[0] || c.Id == res.getUpdatedRelatedIds()[1]) {
54            flag2 = true;
55        }
56            
57        Assert.isTrue(flag1); 
58        Assert.isTrue(flag2);  
59            
60    } else {
61        for (Database.Error err : res.getErrors()) {
62            // Write each error to the debug output
63            System.debug(err.getMessage());
64        }
65    }
66}

Merge Considerations

When merging sObject records, consider these rules and guidelines:

  • Only leads, contacts, cases, and accounts can be merged. See sObjects That Don’t Support DML Operations.
  • You can pass a main record and up to two additional sObject records to a single merge method.
  • Field values on the main record, including null and empty field values, always supersede the corresponding field values on the records to be merged. Therefore, if a field value on the main record is empty, the resulting field value remains empty after the merge operation regardless of the field value on the duplicate record. To preserve a field value from a duplicate record, manually set this field value on the main record before performing the merge.
  • External ID fields can’t be used with merge.