【図解】SOQL の書き方入門|SQL との違い、親子のリレーション、日付リテラル、101エラーまで
このページには広告リンクを含みます。
SOQL の基本の書き方
SOQL の土台は SELECT と FROM の2つの句です。WHERE、ORDER BY、LIMIT は必要に応じて足します。
SELECT Id, Name, Industry
FROM Account
WHERE Industry = 'Media'
ORDER BY Name
LIMIT 10
書くときに最初につまずくのが項目名です。SOQL に書くのは「取引先名」のような表示ラベルではなく、Name のような API 参照名です。カスタム項目やカスタムオブジェクトの名前は __c で終わります。
書き順の感覚は、レポートと似ています。どのオブジェクトの、どの項目を、どの条件で見るかを決めるだけです。Trailhead でも SOQL の作成をレポートの作成になぞらえて説明しています。
SOQL は取得のための言語です。レコードの作成や更新は DML の仕事で、SOQL ではできません。
SOQL と SQL の違い
SQL を少し知っている人が迷う所を表にしました。

| やりたいこと | SQL | SOQL |
|---|---|---|
| 全項目を取る | SELECT * |
ない。項目を列挙するか FIELDS() |
| 表をつなぐ | JOIN ... ON |
リレーションクエリ。任意の結合はできない |
| 列の計算 | Amount * 2 のような式 |
項目リストで計算式は使えない |
| 名前 | 列名 | API 参照名 |
| 文字列の引用符 | データベースによる | 一重引用符のみ。二重はエラー |
| 日付 | 文字列として書くことが多い | 引用符なし。日付リテラルが使える |
| 更新 | UPDATE 文 |
できない。DML を使う |
SELECT * の代わりに FIELDS() を使う
API 51.0 以降は FIELDS() で項目の組を指定できます。項目名が分からないオブジェクトを調べるときに便利です。
SELECT FIELDS(ALL) FROM Account LIMIT 200
| 使う場所 | FIELDS(STANDARD) |
FIELDS(ALL)、FIELDS(CUSTOM) |
|---|---|---|
| Apex | 使える | 使えない |
| Bulk API 2.0 | 使える | 使えない |
| Salesforce CLI | 使える | 行数を制限すれば使える |
| REST API、SOAP API | 使える | 行数を制限すれば使える |
行数の制限は LIMIT 200 以下か、200件以内の ID 指定です。
SELECT Id, FIELDS(ALL) のように重複すると duplicate field selected: Id というエラーになります。項目レベルセキュリティは守られるので、見る権限のない項目は返りません。調査には便利ですが、Apex では使えないため、コードには必要な項目だけを書きます。
親子のリレーションの書き方
JOIN の代わりになるのがリレーションクエリです。向きによって書き方が変わります。

子から親へ:ドットでたどる
取引先責任者(Contact)から親の取引先(Account)の項目を取ります。WHERE でも同じようにたどれます。
SELECT Id, Name, Account.Name
FROM Contact
WHERE Account.Industry = 'Media'
親から子へ:サブクエリを書く
取引先から、ぶら下がる取引先責任者を取ります。FROM に書くのは子リレーション名で、標準オブジェクトでは子オブジェクト名の複数形です。Contact ではなく Contacts と書く点に注意します。
SELECT Name,
(SELECT LastName FROM Contacts)
FROM Account
WHERE Industry = 'Media'
サブクエリの中に WHERE も書けます。冒頭の依頼なら、次の形になります。
SELECT Name,
(SELECT Name, Amount, CloseDate
FROM Opportunities
WHERE IsClosed = FALSE)
FROM Account
カスタムのリレーションは __r
カスタムの参照関係や主従関係では、__c を __r に換えます。オブジェクトと項目の名前は説明のための例です。
子から親へたどるときは、リレーション項目の名前の __c を __r にします。
SELECT Id, Region__r.Name FROM Shop__c
親から子へたどるときは、子リレーション名に __r を付けます。
SELECT Name, (SELECT Name FROM Shops__r) FROM Region__c
開発者コンソールで試すときは、サンプルをまとめて貼らず、1文ずつ実行します。
子から親で使う名前はリレーション項目の名前、親から子で使う名前は子リレーション名です。子リレーション名は項目を作るときに決めるので、迷ったらオブジェクトマネージャーのリレーション項目で確かめます。オブジェクト同士の関係は主従関係と参照関係の違いで図解しています。
| リレーションクエリの上限 | 値 |
|---|---|
| 子から親のリレーション | 1クエリ55個まで |
| 親から子のリレーション | 1クエリ20個まで |
| 子から親の深さ | 5階層まで |
| 親から子の深さ | 5階層まで(API 58.0 以降の REST、SOAP、Apex。親を1階層目と数える) |
親から子の5階層は、Bulk API、Bulk API 2.0、ビッグオブジェクト、外部オブジェクトでは使えません。API 57.0 以前は2階層までです。
WHERE の書き方と日付リテラル
WHERE の値には書き方の決まりがあります。
- 文字列は一重引用符。二重引用符はエラー
- 日付と数値は引用符なし
- チェックボックスは
TRUE、FALSE - 項目名は引用符で囲まない
- 値に別の項目名や計算は書けない(2項目の足し引きで絞る
FORMULA()はベータ版で、WHERE 専用) - AND と OR を混ぜるときは、かっこで順序を決める
SELECT Name, Email
FROM Contact
WHERE LastName IN ('James', 'Barr')
AND (MailingState = 'Tokyo' OR Title LIKE '%部長')
IN は値の並びとの比較、LIKE は % を使ったあいまい一致です。
日付リテラルは「範囲」を表す
日付の条件は、固定の日付でも、相対の日付リテラルでも書けます。項目の型で形式が変わります。
date 型の項目には日付だけを書きます。
SELECT Id FROM Opportunity WHERE CloseDate = 2026-10-31
dateTime 型の項目には日時を書きます。日本時間はオフセットで指定します。
SELECT Id FROM Account WHERE CreatedDate > 2026-10-01T00:00:00+09:00
日付リテラルは、そのまま書きます。
SELECT Id FROM Opportunity WHERE CloseDate = THIS_QUARTER
日付リテラルは1時点ではなく期間です。= は期間の中、> と < は期間の外側という意味になります。たとえば CloseDate > THIS_MONTH は「今月より後」です。
| 日付リテラル | 表す範囲 | 例 |
|---|---|---|
TODAY |
今日 | CreatedDate = TODAY |
YESTERDAY |
昨日 | CreatedDate = YESTERDAY |
THIS_WEEK |
今週 | CloseDate = THIS_WEEK |
THIS_MONTH |
今月 | CloseDate = THIS_MONTH |
LAST_MONTH |
先月 | CreatedDate = LAST_MONTH |
THIS_QUARTER |
今の暦の四半期 | CloseDate = THIS_QUARTER |
THIS_YEAR |
今年 | CloseDate = THIS_YEAR |
LAST_90_DAYS |
90日前から現在まで(今日を含む) | CreatedDate = LAST_90_DAYS |
LAST_N_DAYS:n |
n日前から現在まで(今日を含む) | CreatedDate = LAST_N_DAYS:30 |
NEXT_N_DAYS:n |
明日からn日間(今日を含まない) | CloseDate = NEXT_N_DAYS:15 |
ハマりやすい点が3つあります。
THIS_QUARTERは暦の四半期です。設定の会計年度に合わせるならTHIS_FISCAL_QUARTERを使います。公式は FISCAL 系のリテラルの前提として、カスタム会計年度の定義を挙げています。- 週の始まりなどの範囲は、クエリを実行するユーザーのロケールで変わります。ユーザーに設定がなければ組織のロケールです。
dateTimeは UTC で保存されています。Zを付けて書くと UTC として解釈されるので、日本時間で見たいなら+09:00のようにオフセットを付けます。
SOQL を実行する場所
目的に応じて選びます。最初は開発者コンソールで十分です。
| 場所 | 向いている用途 | 書き方の要点 |
|---|---|---|
| 開発者コンソール | 手で試す、結果を見る | クエリエディターに貼って実行 |
| Salesforce CLI | 結果を CSV や JSON で保存する | sf data query |
| VS Code の拡張 | プロジェクトの中で書く | 拡張の SOQL 機能を使う |
| Apex | 処理の中で使う | 角かっこで囲む |
| REST API | 外部から取得する | q パラメータに渡す |
開発者コンソール
Trailhead の手順では、設定のクイック検索で Web Console を開き、Enable Developer Console を有効にしてページを更新してから、開発者コンソールを起動します。下のパネルの Query Editor タブにクエリを書いて Execute を押します。
File メニューからオブジェクトを開き、項目を選んで Query を押すと、API 参照名の入ったクエリが自動で作られます。名前が分からないときの近道です。
Salesforce CLI
--target-org には接続済みの組織の別名を指定します。CLI の準備はSalesforce CLI の始め方で説明しています。
sf data query --query "SELECT Id, Name FROM Account LIMIT 10" --target-org my-dev
sf data query --file query.txt --result-format csv --output-file output.csv --target-org my-dev
10,000件を超えそうなときは、公式の説明どおり sf data export bulk を使います。
Apex
Apex では角かっこで囲み、変数はコロンを付けて渡します。
String industry = 'Media';
List<Account> accounts = [
SELECT Id, Name FROM Account WHERE Industry = :industry
];
試す組織がなければDeveloper Edition の作り方を先に見てください。
よくあるエラーと直し方
| エラーや症状 | 原因 | 直し方 |
|---|---|---|
Too many SOQL queries: 101 |
1トランザクションで SOQL が100回を超えた | ループの外で1回にまとめる |
Too many query rows: 50001 |
取得行の合計が50,000行を超えた | WHERE で対象を絞る、処理を分ける |
Non-selective query against large object type |
大きなオブジェクトで、選択的な絞り込みがない | 索引のある項目で絞る、Query Plan で調べる |
duplicate field selected: Id |
項目リストの重複 | FIELDS() と個別の項目が重ならないようにする |
QUERY_TOO_COMPLICATED |
文が長く複雑(数式項目が多いなど) | 取る項目を減らす |
| 文字列の引用符のエラー | 二重引用符を使った | 一重引用符に直す |
| CLI で件数が多い | sf data query は既定の API を使う |
sf data export bulk に換える |
ガバナ制限のうち、SOQL に関わる値は次のとおりです。
| 上限 | 同期 | 非同期 |
|---|---|---|
| SOQL の回数 | 100 | 200 |
| SOQL で取得する合計行 | 50,000 | 50,000 |
| 親子のサブクエリの数 | トップレベルの回数の上限の3倍 | 同左 |
非同期はバッチ Apex や future メソッドの値で、スケジュール Apex には同期の上限が適用されます。サブクエリを含む SOQL は、親子リレーションごとに追加のクエリとして数えられます。ガバナ制限の例外は捕捉できず、処理が止まります。
101 エラーの直し方
ヘルプの例は、取引先のトリガの for ループの中で取引先責任者を取るコードです。取引先が101件まとめて処理されると、101回目で止まります。

// やってはいけない形:1件ごとに SOQL を使う
for (Account a : Trigger.new) {
List<Contact> cons = [SELECT Id FROM Contact WHERE AccountId = :a.Id];
}
// 直した形:ID を集めて、ループの外で1回だけ
Set<Id> accountIds = new Set<Id>();
for (Account a : Trigger.new) {
accountIds.add(a.Id);
}
List<Contact> cons = [
SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds
];
この上限は、同じトランザクションのトリガ、クラス、フローの分も合算されます。ヘルプによれば引き上げもできません。フローで同じことが起きる場合の考え方はフローのループ内の更新を直す記事に書きました。同じトランザクションで何が動くかは保存時の実行順序で確かめられます。
SOQL が向かない場面
レポートと SOQL は、どちらかが上位というものではありません。
- 営業の担当者が自分で条件を変えて見るなら、レポートとダッシュボードが向きます。
- どのオブジェクトにあるか分からない語を探すなら、SOQL ではなく SOSL を使います。公式は、対象のオブジェクトや項目が分からないときの選択肢として SOSL を挙げています。
- レコードを大量に更新するなら、データ操作の道具を使います。データローダの使い方を見てください。
関連記事
- Developer Edition の作り方:SOQL を無料で試す環境を用意する
- Salesforce CLI の始め方:コマンドから組織につなぐ
- 主従関係と参照関係の違い:リレーションクエリの土台
- フローのループ内の更新を直す:同じガバナ制限の話
- Platform App Builder の勉強法:データモデルを試験範囲とつなげて学ぶ
よくある質問
- SOQL と SQL の違いは何ですか?
- SOQL は Salesforce のデータを取得するための言語で、書き方は SQL の SELECT に似ています。ただし SELECT * のような項目のワイルドカード、任意の JOIN、計算式は使えず、オブジェクト間はリレーションクエリでたどります。
- SOQL で SELECT * の代わりに全項目を取るには?
- FIELDS(ALL) を使います。API 51.0 以降で使え、CLI や API では LIMIT 200 以下などで行数を制限する必要があります。Apex では FIELDS(ALL) と FIELDS(CUSTOM) は使えないので、項目を列挙します。
- SOQL で親オブジェクトの項目を取るにはどう書きますか?
- 子から親へはドットでたどります。取引先責任者から取引先名を取るなら SELECT Id, Account.Name FROM Contact です。カスタムのリレーションは項目名の __c を __r に換えます。
- SOQL の日付の条件に引用符は必要ですか?
- 不要です。SOQL の日付と数値には引用符を付けません。WHERE CreatedDate = THIS_MONTH のように日付リテラルをそのまま書くか、date 型の項目なら 2026-10-01、dateTime 型の項目なら 2026-10-01T00:00:00+09:00 の形で書きます。
- Too many SOQL queries: 101 はどう直しますか?
- 1トランザクションで SOQL が100回を超えたときのエラーです。ループの中の SOQL をやめ、先に ID を集めてからループの外で IN を使った1回のクエリにまとめます。