Hello and thank you in advance. I'm looking to merge about 2000 records (about 1000 merges in total). My question is whether there is a best practices for this type of task. I'm able to merge 1 set of contacts via Execute Anonymous in the Developer Console:

Contact con = [select id,fax,phone from contact where id='xxxxx'];
Contact con2 = [select id,fax,phone from contact where id='xxxxx'];
database.merge(con, con2);

I would imagine I will need to employ a collection of tuples and do a foreach on them to handle the merging. Where do I start here, as far as storing a collection of tuples (e.g. {keeper1, mergee1},{keeper 2, mergee2})? Would I create a custom object that would house the tuples I intend to use for merging and then loop through them? When I have the Apex script written should I execute via the Execute Anonymous, or should I create a class to handle the work and invoke this a different way? Any help is greatly appreciated and sorry if my explanation is lacking.

2 Answers 2


Use a custom object so you can load them quickly. Use a class so you can process those all in one batch go. Because of DML limits, you won't be able to just execute anonymous, unless you feel like running your script hundreds of times.

For the custom object, use two lookup fields, the account to merge to, and the account to merge from. You could include a "status" field to indicate success/failure.

For your class, a simple batch class works:

public class BatchMerge implements Database.Batchable<Merge_Record__c> {
    public Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator([SELECT Merge_To_Account__c, Merge_From_Account__c FROM Merge_Record__c]);
    public void execute(Database.BatchableContext context, Merge_Record__c[] records) {
        for(Merge_Record__c record: records) {
            try {
                Database.merge(new Account(Id=record.Merge_To_Account__c), record.Merge_From_Account__c);
                record.Status__c = 'Success';
            } catch(exception e) {
                record.Status__c = 'Failed';
        update records;
    public void finish(Database.BatchableContext context) {

Make sure when you call your script, it uses a small enough scope size (not 200) to accommodate the massive number of DML statements you'll wrack up using this code:

Database.executeBatch(new BatchMerge(), 10);

Adjust this size to suit your needs.

  • What exactly does the custom object accomplish? Does it have just two lookups to contacts? Several pairs? Kind of hard for me to suss out what you are actually recommending.
    – Adrian Larson
    Commented Nov 12, 2015 at 19:04
  • @AdrianLarson We just implemented this not too long ago (last week or so); here's the basic skeleton of what we did. It works like a champ, and is easy to implement (I typed up the code in the answer in less than 7 minutes).
    – sfdcfox
    Commented Nov 12, 2015 at 19:12
  • @sfdcfox Much appreciated, that info is very helpful. Dumb question, but once I have the class created to do the work, how/where do I invoke the class?
    – tchock
    Commented Nov 12, 2015 at 19:16
  • @parrotsnest No, that's a legit question. For a simple one-time-use scenario, just use the Developer Console and run it from there (use the last script line in the answer). For times when you might want to run this, say, every day, you can write a quick scheduled class and run it from there.
    – sfdcfox
    Commented Nov 12, 2015 at 19:22
  • @sfdcfox So run the last line (to invoke) via Execute Anonymous?
    – tchock
    Commented Nov 12, 2015 at 19:34

Below simple, not (code) efficient but effective script have saved me tons of hours. Run in DevCons or Workbench ....

//** Tweak your account selection ... aka where clause ..
List<AggregateResult> MyMergeList = [select count(id), name from account 
where Origin__c = 'Lead' group by name  having count(id) >1 limit 25];

For (AggregateResult Agm:MyMergeList){

   //** Tweak the string parameters to match your preference 
   // String accName = '%'+ string.valueOf(agm.get('Name')) + '%';
   String accName = string.valueOf(agm.get('Name'));
   Account ToAccount = [Select id, name from account where name like :accName limit 1];
    Account FromAccount = [Select id, name from account where Id != :ToAccount.Id and name like :accName Limit 1];

   system.debug(LoggingLevel.Info,'*** FromAccount: ' + FromAccount.Name+' ('+FromAccount.Id+')');
   system.debug(LoggingLevel.Info,'*** ToAccount  : ' + ToAccount.Name+' ('+ToAccount.Id+')');
   database.merge(ToAccount , FromAccount );


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .