Apex

親子のレコードをSOQL1回でまとめて取得する書き方

親のレコードを取ってから子をループで引き直すと、件数が増えた日に止まります。親子は1回のSOQLで取れます。ドット記法とサブクエリの使い分けと、リレーション名でつまずく場所を書きます。

2025.07.17

なぜ1回にまとめるのか

取引先を取ってから、1件ずつ取引先責任者を引き直す。動きはしますが、これはループの中にSOQLを置く形です。Apexのガバナ制限は1トランザクションあたりのSOQL発行回数を数えるので、親の件数が増えた日に、ある日突然止まります。

SOQLは親子をまたいで1回で取れます。回数が1回で済むだけでなく、コードも短くなります。

向きが2つある

向き書き方例
子 → 親ドット記法取引先責任者から、その取引先の名前を取る
親 → 子サブクエリ取引先から、ぶら下がる取引先責任者を取る

この2つは書き方がまったく違います。同じ「参照関係」でも、たどる向きで形が変わります。

子から親をたどる

参照項目にドットをつなげます。取引先責任者から取引先を見るなら、次のようになります。

SELECT Id, Name, Account.Id, Account.Name
FROM Contact
WHERE Account.Industry = 'Banking'

開発者コンソールのクエリエディタでそのまま実行できます。読み取りだけです。

ドット記法は WHERE でも使えます。上の例は、取引先の業種で取引先責任者を絞り込んでいます。親の項目で子を絞れるのが、この向きの強みです。

クエリエディタの入力欄。Account.IdとAccount.Nameをドット記法で指定したSOQLが1行入っている
実際に打ったクエリです。FROMはContactのまま、SELECTにAccount.Nameを並べている点を見てください。
クエリ結果。Id、Name、Account.Id、Account.Nameの4列が1行で返っている
結果です。親の項目がそのまま列として並びます。1件の行に親の値が横に付く形になります。

カスタムオブジェクトのときは、参照項目の API 参照名の __c を __r に置き換えます。

SELECT Id, Name, Parent__r.Id, Parent__r.Name
FROM ChildObject__c

カスタムの参照項目 Parent__c をたどるときは Parent__r と書きます。

公式リファレンスは「リレーション名を使うときは __c を外し、代わりに __r を付ける」と明記しています。

クエリエディタの入力欄。Parent__r.IdとParent__r.Nameを指定したSOQLが入っている
カスタムの例です。項目のAPI参照名はParent__cですが、たどるときはParent__rと書きます。
クエリ結果。Parent__r.IdとParent__r.Nameの列に親レコードの値が入っている
列名がParent__r.Nameになって、親の名前が返っています。標準の取引先のときと同じ形です。

親から子をたどる

SELECT の中に、丸カッコでサブクエリを置きます。

SELECT Id, Name,
  (SELECT Id, LastName FROM Contacts)
FROM Account
WHERE Industry = 'Banking'

取引先と、その取引先にぶら下がる取引先責任者を1回で取ります。

丸カッコの中の FROM に書くのは、オブジェクト名ではなくリレーション名です。ここが最初のつまずき所です。

クエリエディタの入力欄。丸カッコの中にFROM ContactsのサブクエリがあるSOQL
丸カッコの中を見てください。FROMの後ろがContactではなくContactsになっています。
クエリ結果。Contacts列に子レコードのIdが4件分のJSONで入っている
結果のContacts列です。親1行の中に、子が配列でまとまって入っているのがわかります。
標準オブジェクトのリレーション名は、子オブジェクトの複数形です。取引先責任者なら Contacts、商談なら Opportunities。カスタムオブジェクトは、参照項目を作ったときに決めた「子リレーション名」に __r を付けた形になります。既定では複数形にはなりません。

カスタムオブジェクトの例です。

オブジェクトマネージャの詳細。API参照名がParentObject__c、表示ラベルが親オブジェクト
例で使う親オブジェクトです。API参照名がParentObject__cで、クエリのFROMにはこれを書きます。
オブジェクトマネージャの詳細。API参照名がChildObject__c、表示ラベルが子オブジェクト
子オブジェクト側です。こちらがParentObject__cへの参照項目を持っているほうになります。
親オブジェクトのレコード詳細。下に子オブジェクトの関連リストが1件ぶら下がっている
画面ではこう見えます。親レコードの下にぶら下がる関連リストが、サブクエリで取れる中身です。
SELECT Id, Name,
  (SELECT Id, Name FROM Childs__r)
FROM ParentObject__c

子リレーション名が Childs のとき、サブクエリでは Childs__r と書きます。

リレーション名を確かめる場所

推測で書くと動きません。画面で確かめられます。

  1. 設定からオブジェクトマネージャを開く

    子オブジェクト(参照項目を持っているほう)を選びます。

  2. 項目とリレーションを開く

    親をさしている参照項目をクリックします。

  3. 子リレーション名を見る

    「子リレーション名」に書かれている値が、サブクエリで使う名前です。これに __r を付けます。

取引先責任者の項目「取引先名」の詳細画面。子リレーション名にContactsと表示されている
標準の例です。右側の「子リレーション名」がContactsで、これがサブクエリに書く名前です。
カスタム項目Parent__cの詳細画面。下段の子リレーション名にChildsと表示されている
カスタムの例です。API参照名はParent__cですが、下段の子リレーション名はChildsで別物です。

⚠️ 子リレーション名は、項目を作った人が決めた文字列です。組織によって違います。他社の記事に出てくる名前をそのまま使っても通りません。

クエリエディタの入力欄。サブクエリのFROMにChilds__rと書かれたSOQL
画面で確かめたChildsに__rを足して、Childs__rと書いています。ここを間違えると通りません。
クエリ結果。Childs__r列に子レコードのIdとNameがJSONで入っている
列名がChilds__rになって、子が入って返ってきました。これで1回のクエリで親子が揃います。

Apexで受け取る

サブクエリの結果は、親のレコードの中にリストとして入っています。

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

for (Account a : accounts) {
  for (Contact c : a.Contacts) {
    System.debug(a.Name + ' / ' + c.LastName);
  }
}

親を1回取るだけで、子も一緒に手に入ります。ループの中にSOQLはありません。

子のリストは、サブクエリで取ったときだけ入ります。サブクエリを書かずに a.Contacts を触ると、実行時に例外になります。

どこまでたどれるか

公式リファレンスに上限が書かれています。数が多いように見えますが、複雑なクエリを書くと意外に当たります。

向き1つのクエリで使える数たどれる階層
子 → 親55リレーションまで5階層まで
親 → 子20リレーションまでAPI 58.0 以降は5階層まで

⚠️ 親から子の階層は、APIバージョンで変わります。API 57.0 以前は2階層までで、5階層になったのは 58.0 からです。しかも5階層が使えるのは REST・SOAP・Apex で、ビッグオブジェクト・外部オブジェクト・Bulk API は対象外です。古い apiVersion のまま置いてあるクラスでは、2階層で止まります。

ここで間違えやすい

間違い何が起きるか
サブクエリの FROM にオブジェクト名を書くコンパイルが通りません。リレーション名を書きます
カスタムの参照で __c のまま書く同じく通りません。__r に置き換えます
子リレーション名を他組織の記事から写す名前は組織ごとに違うので通りません
サブクエリを書かずに子のリストを触る実行時に例外になります
古い apiVersion のまま3階層以上のサブクエリを書く57.0 以前では通りません

確認した環境

  • 2026年9月 / Salesforce Summer '26(APIバージョン 67.0)時点の公式リファレンスで、上限とリレーション名の決まりを確認しています

まとめ

  • 親子は1回のSOQLで取れます。ループの中でSOQLを発行しないでください
  • 子から親はドット記法、親から子はサブクエリ。向きで書き方が変わります
  • サブクエリの FROM に書くのはリレーション名です。標準は子オブジェクトの複数形、カスタムは子リレーション名に __r を付けた形です
  • 子リレーション名は組織ごとに違います。オブジェクトマネージャの参照項目で確かめてください
  • 上限は、子から親が55リレーション・5階層、親から子が20リレーション・5階層(API 58.0 以降)です

Salesforceの導入・運用についてご相談ください

導入前の検討から、お使いの環境の改修・運用、AIとの連携まで承ります。状況を伺ったうえで、進め方をご提案します。