#if文を使わず、SQLのCASE式でnullを無視した検索を実行する
以下のような形で検索に使用する入力項目がいくつもあった場合に、コントローラー側でif文を使って空欄時とそうでないときの場合分けをするとif/elseがずらーっと並ぶ上、同じようなメソッドをいくつも使ってコードが汚くなるので、SQLでどうにかできないかといろいろ調べてみたところ、SQLのCASE式を使えばif文を使わずに、よりスマートにコードがかけることがわかったので備忘録として残します。
repository.java
@Query(value = "SELECT * FROM mst_asset"
+ " WHERE id = CASE WHEN :id = 0 THEN id ELSE :id END"
+ " AND category_id = CASE WHEN :categoryId = 0 THEN category_id ELSE :categoryId END"
+ " AND admin_name LIKE concat('%', CASE WHEN :adminName = '' THEN admin_name ELSE :adminName END, '%')"
+ " AND asset_name LIKE concat('%', CASE WHEN :assetName = '' THEN asset_name ELSE :assetName END, '%')"
+ " AND delete_flag = false ORDER BY id ASC"
+ , nativeQuery = true)
List<Asset> findByIdAndCategoryIdAndAdminNameAndAssetName(
@Param("id") Integer id,
@Param("categoryId")Integer categoryId,
@Param("adminName") String adminName,
@Param("assetName") String assetName);
どうやら、WHERE句の[カラム名]=[カラム名]の場合には条件としてカウントしないという性質があるらしくそれを、CASE式に応用することで画面で検索キーワードが入力されなかったパラメータを無視してSQLを実行することができるらしい。
上記のコードでは、Integer型の入力欄のパラメーターに関しては空欄のままだとnullとして受け取ってしまうので、その場合はサービスの中でif文を使って0にセットしてます。String型のパラメーターに関しては、入力された際にはそれをサービスの中でトリミングしてconcatを使って部分一致検索にしてます。