1
public class UpdateBrandBatch implements Database.Batchable<sObject>, Database.Stateful {
    final List<SObject> records = new List<sObject>();
    final string query1, query2;

    public updateBrandBatch(){
        query1 = 'select id, brand__c from account';
        query2 = 'select id, brand__c from contact';
    }

    public Iterable<sObject> start(Database.BatchableContext BC) {   
        records.addAll(Database.query(query1));
        records.addAll(Database.query(query2));
        return records;
    }    

    public void execute(Database.BatchableContext BC, List<sObject> scope) {   
        for (sObject c : scope) {
            c.put('brand__c', 'MyBrand');
        }
        update scope;
    }    

    public void finish(Database.BatchableContext BC) { }   

}

Calling this batch from anonymous window using :

Database.executeBatch(new UpdateBrandBatch(), 20);

even though i enter batch size as 20, still getting the exception. There are some 20 million records of account and about 30 million contacts

Thanks

went through question # 60164 here in SOF and as per suggestion tried reducing the batch size but that didnt help.

3
  • Possible duplicate of Please help! First error: Too many query rows: 50001 in my Batch Job
    – Himanshu
    Commented Dec 16, 2015 at 19:47
  • 2
    @Himanshu I disagree. While I suspect this question may be duplicate, that question doesn't help answer this one.
    – sfdcfox
    Commented Dec 16, 2015 at 19:50
  • Hi @sfdcfox I am pointing this answer towards the "Modify your SOQL queries to be more selective and to only bring back the records required for the Contacts,Account in the scope. "
    – Himanshu
    Commented Dec 16, 2015 at 19:56

1 Answer 1

4

You can't query more than 50,000 rows in your start method. You need a QueryLocator. In practice, this probably means you'll need to run your batch twice, once by accounts and then once by contacts. Probably something like this:

public class ProcessRecords implements Database.Batchable<SObject> {
    public String[] queries = new String[] { 'select brand__c from account', 'select brand__c from contact' };
    public Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator(queries.remove(0));
    }
    public void execute(Database.BatchableContext context, SObject[] records) {
    // Do processing here
    }
    public void finish(Database.BatchableContext context) {
       if(!queries.isEmpty()) {
          Database.executeBatch(this, 20);
       }
    }
}

For unit testing, you may need to call your methods directly instead of trying to execute the batches using Test.stopTest(), to avoid chaining errors.

7
  • Thanks sfdcfox. I was able to update brand on individual object using something like above you suggested. But I was asked to update the brand on multiple objects and looking for a common batch class to update everything.
    – sf_user
    Commented Dec 16, 2015 at 20:00
  • 2
    @pmvsdt As my code demonstrates, it is a common class that runs over both accounts and contacts. The point is, you need to run through twice-- once per sobject.
    – sfdcfox
    Commented Dec 16, 2015 at 20:06
  • Thanks sfdcfox. Will work on this and keep posted here but this sounds like a definite solution for me. Thankyou
    – sf_user
    Commented Dec 16, 2015 at 20:14
  • 1
    @javanoob No, we're not constructing a new class, so it retains the queries in the order they're defined. The only time you have to worry about the class not retaining changes is during the execute method.
    – sfdcfox
    Commented Dec 17, 2015 at 0:18
  • 1
    @pmvsdt You're welcome! I dedicate many hours a week to this site to help people, so this means a lot to me. I'm glad you found this useful.
    – sfdcfox
    Commented Dec 18, 2015 at 7:10

You must log in to answer this question.

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