【PostgreSQL+Spring Data JPA】RepositoryでLIKE ANY(:バインド変数)を実行する方法

プログラミング等

どうもこじらです。

LIKEとIN句を組み合わせたくてLIKE ANYをSpringのアプリケーションから実行しようとしたら色々と躓きました。

色々試しまくった結果正しいやり方が分かったので一応共有です。

 

Springのバージョンは3.3.3です。PostgreSQLのバージョンは17.2です。

Hibernateのバージョンは…Springに内包されてるやつだし別にいいか…。

事象

エラーは以下です。

org.postgresql.util.PSQLException: : op ANY/ALL (array) requires array on right side

 

ANYなのに配列渡されてねぇよ。

みたいなエラー内容です。

 

解決方法

LIKEを”~~”に変更したり、バインド変数に::arrayをつけたり迷走しまくりましたが、結果はシンプルでした。

Repositoryインターフェース

修正前のRepositoryインターフェースにおける該当のメソッドはこんな感じです。

原因の範囲はここだけです。

@Meta(comment = "find by name containing")
@Query(value = "SELECT * FROM table_a WHERE name LIKE ANY(:names)", nativeQuery = true)
List<TableA> findByNameContaining(List<String> names);

 

修正後はこうです。

@Meta(comment = "find by name containing")
@Query(value = "SELECT * FROM table_a WHERE name LIKE ANY(:names)", nativeQuery = true)
List<TableA> findByNameContaining(String[] names);

 

メソッドの引数をListから配列に変更しました。

 

原因は、JavaにおけるListをPostgres側における配列にうまくパースできていないことのようで、渡した値が文字列として認識されてしまっていたようです。

 

余談にはなりますが、Listで渡すことを諦めてString型で渡してもうまくいくっちゃうまくいくということ。

‘{%田中%, %高橋%}’みたいな文字列を渡せばうまくいくんだと思います。

まぁ、SQLインジェクション対策って何?みたいな実装方法になるのでやらないですがw

 

IN句の場合、ListというかCollectionクラスの値であればいい感じにパースしてくれていましたが、LIKE ANYのパターンでは、Spring Data JPAだかHibernateだか誰のロジックかは知りませんがSQLをうまく解釈してくれず、文字列として扱ってしまうっぽいですね。

 

Listはうまくいきませんでしたが配列は話が別らしいです。

配列をバインドパラメータに渡した場合、JPQLが検知してPostgresにおける配列にいい感じに変換してくれるらしく、String[]で渡せばSQLで小細工をせずに値を渡すことができます。

 

JavaでのList→配列

Stream#toArrayは初めて使いました。

List<String> nameList = List.of("%田中%", "%高橋%");
String[] nameArr = nameList.stream().toArray(String[]::new);

 

いやースマートだなぁ。

Stream#toList同様にJava16からじゃないとこの書き方できないですけどね。

Java16より前のバージョンの場合、Collectors.toArrayも存在してないっぽいんでStream使わず古き良き変換をした方が良さそうです。

 

“%”をJava上で連結させる必要があるところはスマートじゃないですが、まぁしょうがないか…。

 

ちょっと荒めの記事になってしまいましたが、今回はこんな感じで。

こじらでした

じゃ

タイトルとURLをコピーしました