SalesforceのSOQL(Salesforce Object Query Language)の バインド(Bind Variables) は、Apexコード内で変数を使ってクエリを動的に構築する方法です。
これは、SQLにおける プレースホルダー(?) と同様の役割を果たし、セキュリティやパフォーマンスの向上に役立ちます。
🔹 SOQLのバインド変数とは?
バインド変数を使うと、Apexの変数をSOQLクエリの条件(WHERE
句など)に埋め込むことができます。
バインド変数の記述には、変数の前にコロン(:
)を付けます。
✅ 例:バインド変数を使ったSOQL
String accountName = 'Acme Corporation';
List<Account> accounts = [SELECT Id, Name FROM Account WHERE Name = :accountName];
上記のコードでは、accountName
変数の値 'Acme Corporation' をSOQLのWHERE
句にバインドしています。
🔹 バインド変数を使うメリット
-
SQLインジェクションを防ぐ
- 文字列の連結でクエリを構築すると、悪意のあるデータが注入されるリスクがある。
- バインド変数を使うと、Salesforceが自動的に値をエスケープ処理するため安全。
❌ 悪い例(SQLインジェクションのリスクあり)
String accountName = 'Acme Corporation'; List<Account> accounts = Database.query('SELECT Id, Name FROM Account WHERE Name = \'' + accountName + '\'');
これは、外部から
accountName
に' OR Name != ''
のような文字列が渡されると、不正なクエリが実行される可能性がある。 -
クエリパフォーマンスの向上
- バインド変数を使うと、SalesforceのSOQLエンジンがクエリ計画(Query Plan)をキャッシュしやすくなる。
- 固定値を直接書くよりも、最適化されたクエリ実行が可能になる。
-
コードの可読性・再利用性が向上
- 変数を使うことで、クエリを柔軟にカスタマイズできる。
🔹 バインドできるデータ型
以下のデータ型の変数をバインドできます。
データ型 | 使用例 |
---|---|
String |
:accountName |
Integer |
:recordCount |
Decimal |
:totalAmount |
Boolean |
:isActive |
Date |
:today |
DateTime |
:currentTime |
Id |
:recordId |
Set<T> / List<T>
|
:accountIds (IN句で利用) |
🔹 バインド変数の具体例
① 文字列 (String
) のバインド
String targetName = 'Tech Corp';
List<Account> accounts = [SELECT Id, Name FROM Account WHERE Name = :targetName];
👉 targetName
の値が Tech Corp
なら、その会社のレコードを取得。
② 数値 (Integer
) のバインド
Integer recordCount = 5;
List<Contact> contacts = [SELECT Id, FirstName, LastName FROM Contact LIMIT :recordCount];
👉 LIMIT
句に変数をバインドし、5件だけ取得。
③ 日付 (Date
) のバインド
Date today = Date.today();
List<Opportunity> opps = [SELECT Id, Name FROM Opportunity WHERE CloseDate = :today];
👉 今日の CloseDate
の商談を取得。
④ リスト (List<T>
または Set<T>
) のバインド
複数のIDを検索条件に使う場合、IN
句でバインドできる。
List<Id> accountIds = new List<Id>{'001XXXXXXXXXXXX', '001YYYYYYYYYYYY'};
List<Contact> contacts = [SELECT Id, FirstName FROM Contact WHERE AccountId IN :accountIds];
👉 accountIds
に含まれる AccountId
を持つ Contact
を取得。
⑤ オブジェクト (SObject
) のバインド
SOQLではSObject
全体をバインドできる。
ただし、バインドできるのはそのオブジェクトのIDのみ。
Account acc = [SELECT Id FROM Account WHERE Name = 'Tech Corp' LIMIT 1];
List<Contact> contacts = [SELECT Id, FirstName FROM Contact WHERE AccountId = :acc];
👉 acc
は Account
オブジェクトだが、バインドされるのは acc.Id
。
🔹 バインド変数の制限
-
WHERE句の右側でのみ使用可能
- バインド変数は
WHERE
やLIMIT
句の右側 でのみ使用可能。 -
SELECT
やORDER BY
では使用できない。
❌ NG例
String fieldName = 'Name'; List<Account> accounts = [SELECT :fieldName FROM Account]; // エラー!
- バインド変数は
-
バインド変数のデータ型に注意
-
Set<T>
やList<T>
をIN
句で使う場合、型が一致している必要がある。 -
Date
とDateTime
の違いに注意(DateTime
にはGMT
が含まれる)。
-
🔹 動的SOQL(Database.query)とバインド
Database.query()
を使う場合も、バインド変数を使うことが推奨される。
String targetName = 'Tech Corp';
String query = 'SELECT Id, Name FROM Account WHERE Name = :targetName';
List<Account> accounts = Database.query(query);
👉 Database.query()
でもバインド変数を利用可能。
👉 直接 +
で文字列連結するとSQLインジェクションのリスクがあるため避ける。
🔹 まとめ
項目 | 説明 |
---|---|
バインド変数とは? | Apex変数をSOQLクエリに埋め込む機能 |
メリット | SQLインジェクション防止、パフォーマンス向上、可読性向上 |
バインド可能な型 |
String , Integer , Date , Id , List<T> など |
IN句でリストバインド可能? | 可能 (List<T> や Set<T> を使用) |
動的SOQLでバインド可能? | 可能 (Database.query() で : を使用) |
バインド変数を適切に使うことで、安全でパフォーマンスの高いSOQL を書くことができます!🚀