Intermediate 30 min read

Child Relationship Queries (Subqueries)

By the end of this lesson, you'll be able to:

  • Query a parent record together with a list of its child records in one query
  • Access the resulting child records as a nested List
  • Explain the naming difference between a parent query and a child subquery

Prerequisites: "Parent Relationship Queries"

Querying children with a subquery

List<Account> accounts = [
    SELECT Id, Name,
        (SELECT Id, LastName FROM Contacts)
    FROM Account
];

for (Account acc : accounts) {
    System.debug(acc.Name + ' has ' + acc.Contacts.size() + ' contacts');
    for (Contact con : acc.Contacts) {
        System.debug('  - ' + con.LastName);
    }
}
  1. List<Account> accounts = [ — opens the outer query.
  2. SELECT Id, Name, — the parent's own fields.
  3. (SELECT Id, LastName FROM Contacts) — the nested subquery — pulls every child Contact related to each Account. Note Contacts (plural) here, not Contact.
  4. FROM Account — the parent object.
  5. ]; — closes the outer query.
  6. (blank line)
  7. for (Account acc : accounts) { — loops over the parent records.
  8. System.debug(acc.Name + ' has ' + acc.Contacts.size() + ' contacts'); — this is exactly Module 16's "Nested Collections" idea applied to query results: each Account ends up with its own List<Contact> attached.
  9. for (Contact con : acc.Contacts) { — loops over the nested child records.
  10. System.debug(' - ' + con.LastName); — logs each one.
  11. } — closes the inner loop.
  12. } — closes the outer loop.

Why "Contacts" instead of "Contact"

A parent relationship (previous lesson) uses the object name (Account.Name) because there's exactly one parent. A child relationship uses a relationship name, almost always the plural form (Contacts, Opportunities) because there can be many children — this naming difference is a genuine, common trip-up worth remembering explicitly.

Handling an Account with zero related contacts

Account acc = [SELECT Id, Name, (SELECT Id FROM Contacts) FROM Account WHERE Id = :someAccountId];

if (acc.Contacts.isEmpty()) {
    System.debug('This account has no contacts.');
}
  1. Account acc = [SELECT Id, Name, (SELECT Id FROM Contacts) FROM Account WHERE Id = :someAccountId]; — queries a single account with its subquery of contacts.
  2. (blank line)
  3. if (acc.Contacts.isEmpty()) { — if an Account has no related Contact records, acc.Contacts still returns a valid, empty List<Contact> — never null — so isEmpty() is always safe to call directly, no null-check required first.
  4. System.debug('This account has no contacts.'); — handles the empty case.
  5. } — closes the if.

Exercise

Write a query on Account selecting Id, Name, and a subquery of related Opportunities (Id, Name), then debug how many opportunities the first account has.

Show hint

(SELECT Id, Name FROM Opportunities)

Salesforce: ○ Not connected Connect
APEX

Execution Results

Run your code to see the result.

Child Relationship Queries (Subqueries) Quiz

1. What does acc.Contacts return for an Account with zero related Contact records?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

A child relationship query (or subquery) pulls a parent record and every one of its related child records in a single query — the reverse direction from the previous lesson's parent traversal.