久しぶりにApexでSOQLのサブクエリを使いました。
久しぶりすぎて、これって結局どんなレコードが取得するんだっけ?となったので整理がてら記事にしてみました。
SOQL初学者には参考になるかもです。
サブクエリとは
SalesforceのSOQL(Salesforce Object Query Language)におけるサブクエリとは、クエリの中でさらに別のクエリを実行することを指します。
どんな時に使用するかというと、親オブジェクトと子オブジェクトの関連情報を一度に取得したい場合に使用します。
もっと具体的に言うと、取引先を取得すると同時にその取引先に子オブジェクトとして紐づいている商談や取引先責任者を一度に取得できるということです。
めちゃ便利!
オブジェクトごとにクエリを実行するでもよいのですが、ガバナ制限に抵触しないためにも、なるべくサブクエリを使用するほうが良いかと思います。
親オブジェクトと子オブジェクトの関連情報を一度に取得したい場合に使用するSOQLの種類
サブクエリの階層
最大5階層の親-子リレーション
サブクエリの特徴として最大5階層の親-子リレーションを含めることができます。
どういうことかというと、親の子の、さらにその子の、さらにその子の、さらにその子の情報まで取得できるということです。
ちなみにこんな感じになる↓
SELECT Name,
(SELECT LastName,
(SELECT AssetLevel,
(SELECT Description,
(SELECT LineItemNumber FROM WorkOrderLineItems)
FROM WorkOrders)
FROM Assets)
FROM Contacts)
FROM Account
ここまで階層が深くなると逆にパフォーマンス落ちそうなので分けてクエリしたほうがいいかもなあ、とか思ったりしています。
まあ、技術的には可能という話ですね。
基本の使い方
まずはサブクエリの最も基本的な使い方です。
以下の例ではAccount
オブジェクト(親)に関連するContact
オブジェクト(子)のレコードを取得しています。
SELECT Id, Name,
(SELECT LastName FROM Contacts)
FROM Account
サブクエリを使用する時は括弧で子レコードを取得するSOQLを囲みます。
この時、注目したいので取引先責任者の取得オブジェクトがContact
ではなく、Contacts
となっている点です。
実はサブクエリで子レコードを取得する際、FROMに指定する子リレーション名は通常のSOQLの場合と異なります。
- 標準オブジェクトのサブクエリでは、リレーション名は子オブジェクトの複数形の名前(子レコードは複数存在するから複数形ってことですね。)
- Contact → Contacts
- Opportunity → Opportunities
- カスタムオブジェクトのサブクエリでは、参照項目で定義した名前
活用ケース
サブクエリ活用のいろいろなパターンのご紹介です。
結局何が取得できるんだっけ?となったときのご参考に。
ケース① – 条件なし
まずは、条件指定も何もない基本ケースから。
以下の例はAccount
(親)に関連するContact
(子)のレコードを取得しています。
SELECT Id, Name,
(SELECT LastName FROM Contacts)
FROM Account
このSOQLによって取得できるデータは以下の通りです。
- 取引先レコード全件(取引先責任者の有無にかかわらない)
- それぞれの取引先に紐づく取引先責任者レコード
ケース② – メインクエリに条件あり
次の例では取引先名が「株式会社OSAKA TOWN」のAccount
(親)に関連するContact
(子)のレコードを取得しています。
SELECT Id, Name,
(SELECT Id FROM Contacts)
FROM Account Where Name = '株式会社OSAKA TOWN'
このSOQLによって取得できるデータは以下の通りです。
- 取引先名が「株式会社OSAKA TOWN」の取引先レコード
- 「株式会社OSAKA TOWN」に紐づく取引先責任者レコード
ケース③ – サブクエリに条件あり
次の例ではAccount
(親)に関連する、名前が「田中 太郎」のContact
(子)のレコードを取得しています。
SELECT Id, Name,
(SELECT Id, LastName FROM Contacts Where LastName = '田中 太郎')
FROM Account
このSOQLによって取得できるデータは以下の通りです。
- 取引先レコード全件(取引先責任者の有無にかかわらない)
- それぞれの取引先に紐づく名前が「田中 太郎」の取引先責任者レコード
ケース④ – メイン / サブクエリに条件あり
次の例では、取引先名が「株式会社OSAKA TOWN」のAccount
(親)に関連する、名前が「田中 太郎」のContact
(子)レコードを取得しています。
SELECT Id, Name,
(SELECT Id, LastName FROM Contacts Where LastName = '田中 太郎')
FROM Account Where Name = '株式会社OSAKA TOWN'
このSOQLによって取得できるデータは以下の通りです。
- 取引先名が「株式会社OSAKA TOWN」の取引先レコード
- 「株式会社OSAKA TOWN」に紐づく名前が「田中 太郎」の取引先責任者レコード
ケース④ – 準結合
準結合は、サブクエリの結果に存在するレコードだけを取得するために使用されます。
次の例ではAccount
(親)レコードの中で、Opportunity
(子)レコードを持つをAccount
のみを取得しています。
SELECT Id, Name FROM Account WHERE Id IN (SELECT AccountId FROM Opportunity)
このSOQLによって取得できるデータは以下の通りです。
- 商談が関連する取引先レコード全件
ケース⑤ – 反結合
反結合は、サブクエリの結果に存在しないレコードを取得するために使用されます。
次の例ではAccount
(親)レコードの中で、Opportunity
(子)レコードを持たないレコードを取得しています。
SELECT Name FROM Account WHERE Id NOT IN (SELECT AccountId FROM Opportunity)
このSOQLによって取得できるデータは以下の通りです。
- 商談が関連しない取引先レコード全件
Apexにおけるサブクエリの活用
ついでに実際にApexで使用する際はこんな感じで使用したりしますよ~というのも記載しておきます。
List<Account> accList = [SELECT Id, Name,
(SELECT LastName FROM Contacts)
FROM Account];
//取引先レコードをループ
for(Account acc : accList){
//その取引先に関連する取引先責任者レコードをループ
for(Contact con : acc.Contacts){
system.debug(acc.Id);
system.debug(con.LastName);
}
}
使い方としては親レコードをループし、そのループ内で子レコードをループして取得する、みたいな感じになります。
多重ループかあ、となりつつ、結局これが手っ取り早いので自分はこの方法を使っています。
まとめ
今回はサブクエリについてあれこれまとめてみました。
親オブジェクトと子オブジェクトの関連情報を一度に取得したい場合に使用するSOQLの種類
親レコードから子レコードに簡単にアクセスできるのは嬉しいですね。
特に準結合と反結合をSOQLで表現できるのはめちゃめちゃ便利です。
レポートのクロス条件を使用するみたいなものですね。
機会があったら使ってみます。
おわりです。
コメント