I am trying to get the highest level of parent account in an Account Hierarchy in Salesforce via Apex and SOQL. I want to create and MAP<Id, Set<Account>> hierarchy in my Apex class to where the highest parent account's Id is the Id in the Map while all the child accounts (or at any level) are in the Set.

I have written the following recursive function to do this but I can't get all the child Accounts in there for the top most parent account.

public class AccountsHierarchy{

    public Map<Id, Account> allChildAccounts {get; private set;}
    private Map<String, Set<Account>> parentAccountMap {get; set;}
    private List<Account> childAccounts {get; set;}

    public AccountsHierarchy(){

        allChildAccounts = new Map<Id, Account>([
                SELECT Id, ParentId, Parent.ParentId
                FROM Account
                WHERE ParentId != NULL
        childAccounts = new List<Account>();
        parentAccountMap = getParentAccountMap();


    private String getParentAccountId(String childAccountId){

        Account localAccount = allChildAccounts.get(childAccountId);
        if(localAccount.Parent.ParentId != null) {

            return getParentAccountId(localAccount.ParentId);

            return localAccount.ParentId;


    public Map<String, Set<Account>> getParentAccountMap(){

        Map<String, Set<Account>> parentAccounts = new Map<String, Set<Account>>();
        for(String childAccountId:allChildAccounts.keySet()){


            String parentAccountId = getParentAccountId(childAccountId);

            if(parentAccountId != null){

                    Set<Account> childAccountsFromMap = parentAccounts.get(parentAccountId);
                    parentAccounts.put(parentAccountId, childAccountsFromMap);
                } else {
                    parentAccounts.put(parentAccountId, new Set<Account>(childAccounts));

        return parentAccounts;

  • Which child accounts are missing? Is it all accounts from a specific level in the hierarchy? May 25 '19 at 5:48
  • All I get are the child accounts at first level. I want to look for all the child accounts from any level in the hierarchy. Jun 6 '19 at 11:34

The best approach to this would be, in my opinion, to create a hidden field to store the Id of the account on the top of the hierarchy, and fill it with a trigger, process or workflow rule.

Scenario 1:

  1. Top account is created
  2. Child account is created, but parent account is not related yet.
  3. User remembers that the accounts are related, and fills the "parent account" field.
  4. Have the system update the "account on top of the hierarchy" field with either the value of the same field on the parent record (if it isn't blank) or fill it with the parent record's Id.

Scenario 2:

  1. Top account and child account are created.
  2. User creates a third account that will now act as the parent for the other two.
  3. User fills the "parent account" on the old parent account record with the new top account created.
  4. Have the system update the "account on top of the hierarchy" field on the child records, if the account is the new parent or not (checking the same field, again).

Scenario 3:

  1. Top account, middle account and bottom account are created.
  2. User creates another account that will sit between two of those.
  3. User fills the "parent account" of the new account with the referente of any of the accounts currently in the database.
  4. If the account selected as parent is the top one, check if the "account on top of the hierarchy" field of the parent record is empty. If it is not, then the created account should copy the parent's account field. If it is empty, then the parent account is the top account, and the system should copy the account Id instead.

These should cover the most common scenarios, I believe. That way you will not have to worry about hitting governor limits when searching for the account on top.

It might be a good thing to do a little research if there is such situation where multiple accounts are linked through the ParentId field. If there aren't that many levels, then you'll probably be fine using the query inside the loop as an exception, because it is indeed simpler than doing all this. But if you don't know how many accounts can be nested or the business requires that the accounts are nested, then it might be a good idea to invest some time in this kind of solution.

  • 1
    Actually, this is very neat the way you explained it. I forgot to mention in my last post about there's an external system integrated with Salesforce and it keeps it's own record of heirarchy and top most parent account ids in the system. And I used that (by importing that id info as a custom field) and do the similar iteration. I have had success with this this issue. Jun 7 '20 at 19:07
  • 1
    Although, if there wasn't any involvement of the external system with Salesforce Accounts I'd definitely prefer what you have suggested, and in a way I am following the similar approach except I don't have to copy the value of top most parent on the child accounts it's done by the external system itself. Rest of the process is the same. Jun 7 '20 at 19:10

I am working on a similar issue I found alot of help and a solution to this using the following website


    //find highest parent account from a child
public id findTopLevelParent(account a) {
    Boolean isTopLevelAccount = false;
    account acct = new account();
    id currAcctId = a.id;

    while (!isTopLevelAccount) {

        acct = [select Id, ParentId From Account where Id = :currAcctId limit 1];
        if (acct.ParentID != null) {
            currAcctId = acct.ParentID;
        } else {
            isTopLevelAccount = true;

    return currAcctId;   

From that website I Got this piece of code working.

Update: As for the Map part, heres the link to the flushed out method from that link I shared earlier.

I do not know if this is the best solution, So definetly open to critique

  • Do you think it is the best way to do this? I have the possible data set of 10,000 Accounts and since the query is in the loop, this will definitely fail at some point due to Governor limits. Jun 18 '19 at 14:44
  • Also the point is not just get the Top Level Parent but also to create a Map using the Parent Id with the Set of Child Accounts . Jun 18 '19 at 14:48
  • @AnasRashid yeah it definitely will flirt the line of governor limits haha. I Updated my post to include my other thread that is on the same topic. That method works but its definitely resource hog. I am looking for better ways to accomplish this as well Jun 18 '19 at 14:54

Here is the most aggressive SOQL query available to find the top level Account from any starting Account Id:

select ParentId, Parent.ParentId, Parent.Parent.ParentId,
Parent.Parent.Parent.ParentId, Parent.Parent.Parent.Parent.ParentId,
Parent.Parent.Parent.Parent.Parent.ParentId from Account where

Here is an example with the maximum of 6 Parent Ids returned. If you still have not reached the top ParentId=NULL then you must recurse on the last returned Parent Id and run the query again until you get there.

    <result xsi:type="QueryResult">
        <queryLocator xsi:nil="true"/>
        <records xsi:type="sf:sObject">
            <sf:Id xsi:nil="true"/>
            <sf:Parent xsi:type="sf:sObject">
                <sf:Id xsi:nil="true"/>
                <sf:Parent xsi:type="sf:sObject">
                    <sf:Id xsi:nil="true"/>
                    <sf:Parent xsi:type="sf:sObject">
                        <sf:Id xsi:nil="true"/>
                        <sf:Parent xsi:type="sf:sObject">
                            <sf:Id xsi:nil="true"/>
                            <sf:Parent xsi:type="sf:sObject">
                                <sf:Id xsi:nil="true"/>

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.