Labyrinth of Wisdom

-This is My Archive-


複数条件での検索 (動的SOQL)

複数の入力フォームに値を入力し、その値を検索条件として値を取得するコードのサンプルです。 例えば下記の様なフォームがあるとします。



このフォームの場合、レコードの検索条件としては下記の4パターンが考えられます。

・名前も年齢も入力されていない
 →全てのレコードを取得

・名前のみ入力されている
 →名前の前方・後方一致で当てはまるレコードを取得

・年齢のみ入力されている
 →年齢が一致するレコードを取得

・名前も年齢も入力されている
 →名前が前方・後方一致かつ、年齢が一致するレコードを取得

つまりユーザの操作によって4パターンのSOQLが発行されることになります。

if(String.isBlank(inputName) && String.isBlank(inputAge)){
    // 名前も年齢も入力されていない
    Hoge__c[] hogeList = [SELECT Name, Age__c FROM Hoge__c];
}else if(!String.isBlank(inputName) && String.isBlank(inputAge)){
    // 名前のみ入力されている
    Hoge__c[] hogeList = [SELECT Name, Age__c FROM Hoge__c WHERE Name LIKE :name]
}else if(String.isBlank(inputName) && !String.isBlank(inputAge)){
    // 年齢のみ入力されている
    Hoge__c[] hogeList = [SELECT Name, Age__c FROM Hoge__c WHERE Age__c = :age]
}else{
    //名前も年齢も入力されている
    Hoge__c[] hogeList = [SELECT Name, Age__c FROM Hoge__c WHERE Name LIKE :name AND Age__c = :age]
}

この方法では、WHERE句のみが違う同じようなコードを何回も書かないといけません。 今回は入力フォームが二つなので4パターンで済みますが、これがもっとたくさんある場合はその都度同じようなSOQLの文を書かないといけないので面倒です。

おまけに名前の検索時は%田中%みたいに自分でワイルドカード(%)を付けてやらないと前方・後方一致検索できません。

これを解決するのが動的SOQLと呼ばれるものです。 先ほどのコードに書いてあるSOQLは静的SOQLと呼ばれます。

動的SOQLはDatabase.query(String)メソッドを使用して、引数に文字列でSOQL文を渡してやることでレコードを取得します。

// 静的SOQL
Hoge__c[] hogeList = [SELECT Name, Age__c FROM Hoge__c];

// 動的SOQL
Hoge__c[] hogeList = Database.query('SELECT Name, Age__c FROM Hoge__c');

動的SOQLはSOQL文が文字列なので、Database.query(String)メソッドを呼び出す前に、条件分岐でsoql文を作り変えてやれば画面の入力値に応じて発行されるsoql文が変化します。

先ほどの静的SOQLで書いたコードを動的SOQLで書き直したコントローラのサンプルコードを記載します。

public class SampleSearchController {

    // フォーム入力用変数
    public String inputName {get;set;}
    public String inputAge {get;set;}

    // 検索するオブジェクト
    public Hoge__c[] hogeList{get;set}

    // コンストラクタ
    public SampleSearchController(){
    hogeList = new List<Hoge__c>();
    }

    // 検索メソッド
    public void search(){
        String soql = 'SELECT Id, Name, Age__c FROM Hoge__c';
        String where = ' WHERE '
        String soqlName = 'Name LIKE \'%' + String.escapeSingleQuotes(inputName) + '%\'';
        String soqlAge = 'Age__c = ' + String.escapeSingleQuotes(inputAge);

        if(!String.isBlank(inputName) && !String.isBlank(inputAge)){
            // 名前も年齢も入力されている
            soql += where + soqlName + ' AND ' + soqlAge;
        }else if(!String.isBlank(inputName) && String.isBlank(inputAge)){
            // 名前のみ入力されている
            soql += where + soqlName;
        }else if(String.isBlank(inputName) && !String.isBlank(inputAge)){
            // 年齢のみ入力されている
            soql += where + soqlAge;
        }

        System.debug(soql);
        hogeList = Database.query(soql);
    }

}

このようにSOQL文を文字列で扱うことで、入力された値によって動的にSOQL文を変化させることが出来ます。 ついでにワイルドカード(%)も変数の中に埋め込んでいるので、入力フォームにワイルドカード(%)を入れなくても前方・後方一致検索ができます。