I have the following method called from a trigger, which calls another method which has SOQL in it. I want to remove that query from the method so that I will not face governer limits issues in the future.

public static void METHOD1 (){
    for(Account acc: mapOfTriggeredAccounts){
        Account topAccount = getTopParentAccount(acc.ID);
        // business logic

//METHOD 2 : Method to get Top Level Parent Account in Hierarchy
public static Account getTopParentAccount(Id currAcctId) {
    Boolean isTopLevelAccount = false;
    Account acct;

    while (!isTopLevelAccount) {
        ////// **** THIS IS IT **** 
        acct = [SELECT ID, ParentId FROM Account WHERE ID = :currAcctId LIMIT 1]; 
        if (acct.ParentID != null) {
            currAcctId = acct.ParentID;
        } else {
            isTopLevelAccount = true;
    return acct;

So as you can see in the code - my SOQL from getTopParentAccount gets called in the FOR LOOP of METHOD1. Can anyone help me out here to take this SOQL out?


  • If you say use MAP{parentID,Account} to store the "ALL" accounts and their ParentID's in it. That might be something crazy as per my point of view!
  • Because I don't think of any condition here to control/ narrow down no.of Accounts.

Not useful but just for reference, I am working on this !

  • Any suggestions?
  • Any Links/Docs?
  • Any Examples?
  • 1
    I would suggest to query parents of accounts for list of all given accounts as long as there are those parent accounts. and store them in map Here you can see something similar salesforce.stackexchange.com/questions/96643/… -- we query groups, that have child groups as long as there are no child groups, only members – kurunve Jan 13 '16 at 13:58
  • 1
    I think that a map<Account, ParentId> is the way to go. You don't need all the accounts, just for the accounts you were given initially. But you may have to do several queries to find the top parent of an account, it might be easier to just load them all in memory with a query. – mkorman Jan 13 '16 at 14:13

Because you're only doing this for one account, this isn't the same situation as where you'd be doing it for a great number of accounts. That having been said, this method would best be called by sending a set of accounts and refactoring your code. Doing that would make it more efficient and reduce the number of queries.

Your code would look something like this:

public static Account2ParentMap getTopParentAccount(set<Id> AcctIds) {
    map<Id,Id>Child2Parent = new map<Id,Id>()
    list<Account>Accnts = new list<Account>();
    set<Id>Accts = new set<Id>();

    While(Accts.size() > 0)
        list<Account>accnts = [SELECT ID, ParentId FROM Account WHERE ID IN :Accts ]; 

        for(Account a:accnts){
            if (a.ParentID != null) {  
                //put record into map 
            if(a.ParentID == null) {
                //remove account with parent from list of accounts to query
                //since this means parentId == null


         if(Actcs.size() == 0) break;   
    // return map of accounts 2 ulitmate parent account
    return Child2Parent;
| improve this answer | |
  • 1
    If AcctIds contains 101+ unique existing accountIds this will break. Query in while loop is not bulkified. – Peter de Jong Jan 13 '16 at 14:32
  • No, it would only break if there's 101 levels to reach the top ParentId. It is bulkified as it queries on the set of all Ids and removes Ids that have parentIds as they've been found. I've fixed my comments that were misplaced and added an additional one. – crmprogdev Jan 13 '16 at 14:33
  • Caught into 101 SOQL . Set AcctIds has only one ID in it. – Salesforce Steps Jan 14 '16 at 13:26
  • 1
    Revised code. This should solve the issue. See if this doesn't fix your issue. Is what happens when you write code on the fly. – crmprogdev Jan 14 '16 at 13:52

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.