function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Dhananjay Patil 12Dhananjay Patil 12 

System.QueryException: unexpected token: (ID Value) error occur when calling batch apex class

My Requirement is When I update Classification values on Top Account(Parent Account),it updates values on all child accounts.
I have Written a batch apex class for this as I faced CPU Timeout error earlier.
Below is the code for Batch Apex Class:
global class batchAccountUpdate implements Database.batchable<sObject>{ 
   public String query;
   global database.querylocator start(Database.BatchableContext info){
   system.debug('query Result:'+query);
       String query1='select Id,ParentId,RecordTypeId,UltimateParent__c,AccountCategory__c,Account_Subcategory__c ,AccountClassification1__c, AccountClassification2__c, AccountClassification3__c,AccountClassification4__c, AccountClassification5__c, AccountClassification6__c, AccountClassification7__c, AllowClassificationUpdate__c,Allow_CategorySubCategory_Update__c,BillingCountry,BillingCountryCode from Account where Id='+query+'';
   system.debug('Query1 Result:'+query1);
   system.debug('Start Info:'+info);
    return Database.getquerylocator(query);
    }     
   global void execute(Database.BatchableContext info, List<Account> children){
       
       if (!children.isEmpty()) {
                update children;
            }
   }     
   global void finish(Database.BatchableContext info){     
   } 
}
The purpose of this batch is to perform DML operation only.I have created instance of this class in another apex class where I have written an actual logic.
Below is the Apex class:
public static List<Account> updateClassification(Map<Id,Account> accMap) {
List<Account> accList = findAccountToUpdate(accMap);
// find ultimate accounts with classification fields
Set<Id> utimateIds = new Set<Id>();
for (Account acc: accList) {
utimateIds.add(acc.UltimateParent__c);
}
Map<Id,Account> ultimateMap = new Map<Id,Account>(new SelectAccounts().execute(utimateIds));
SET<ID> keys = ultimateMap.keyset();

// update statistics from ultimates
List<Account> accToUpdate = new List<Account>();
for (Account acc: accList) {
Account parentAccount = ultimateMap.get(acc.UltimateParent__c);
accToUpdate.add(new Account(
Id = acc.Id,
AccountCategory__c = parentAccount.AccountCategory__c,
Account_Subcategory__c = parentAccount.Account_Subcategory__c,
AccountClassification1__c = parentAccount.AccountClassification1__c,
AccountClassification2__c = parentAccount.AccountClassification2__c,
AccountClassification4__c = parentAccount.AccountClassification4__c,
AccountClassification5__c = parentAccount.AccountClassification5__c,
AccountClassification6__c = parentAccount.AccountClassification6__c,
AccountClassification7__c = parentAccount.AccountClassification7__c,    
AllowClassificationUpdate__c = true,
Allow_CategorySubCategory_Update__c = true
));
}
string query= '\''+String.join(keys,'\',\'')+'\'';

//Calling Batch Class
batchAccountUpdate execbatch = new batchAccountUpdate();
execbatch.query = query;
database.executebatch(execbatch);
resetAllowClassificationUpdate(accToUpdate);
resetAllowCategoryUpdate(accToUpdate);

return accToUpdate;
}

Whenever I Update Classification Value son Top Accounts or If I do Reparenting,it always throws an exception whenever it runs the natch class.
I can not add this method to Batch Class as the method has lots of dependency on another methods.
My Ultimate Goal is I whenever I perform DML,I have to call batch job so that CPU Runtime error will not face as I can update more than 200 Child records at a time too.

Can someone help what is wrong in the above code? 
 
Saravana Bharathi 1Saravana Bharathi 1
In the batch, you are not doing anything, just querying and doing update, you are not event assigning any new value to any field.
And on what scenario, Update classification method been called.

As per my understanding,You can handle it in Apex Trigger, Why do you want to handle it in Batch.
Correct me if I am Wrong.

Write a trigger in Account Object, for before update.
Write a logic only if it updates certain conditions (Updating Reparenting or Updating Classifications).
Update all child account with parent's value.
Use Static Boolean to avoid recursive calls.

Thanks
Dhananjay Patil 12Dhananjay Patil 12
@SaravanaBharathi1 The reason that I need to write a btach here is because when it performs DML Operations if no child records of Pranet Account is more(more than 200 child arecords) then I face " System.LimitException: Apex CPU time limit exceeded " error.Thats why I have writeen batch apexx class here and I want to peroform this operation only on certain condition(In this case Updating Classification Fields) thats why I have created Batch class instance in Apex Class method so that whenever it performs DML opration it calls batch class and divides the record into no of batch so that DML perform without having any exception.
The method is already getting called on After Update Trigger.
Saravana Bharathi 1Saravana Bharathi 1
Lets say for a Account there are 200 Child Account. Salesforce in-turns, splits into batches.
Each batch will have only 200 record at a time. So, For 200 parent Account, maximum it can have only 40000.
For apex limit as only 10000 DML Row can be executed.

For this particular case, if you are going for Batch.  Then, even in the batch mode it may fail, if number of child record get increased. 
One more consideration is, in the batch, it updates Account, then again, it fires Update Trigger one-more time.(Avoid recursive call by using static variables).

My suggestions are:

1. Use Static Variables to avoid recursive call.
2. Use Batch size, while calling Batch. Reduce it to 50 or 100 or 150, based on which size, its not failing (Forsee, how many child record can have in your use case as maximum).
3. Check the execute method in Batch, because its just querying and updating, before updating assign required values to assign.

Hope. This Helps.

Thanks