我正在使用一个使用 JPA 和 Postgres 数据库的 Java 应用程序,并且我正在尝试创建一个灵活的准备好的语句,它可以处理可变数量的输入参数。一个示例查询可以最好地解释这一点:
SELECT *
FROM my_table
WHERE
(string_col = :param1 OR :param1 IS NULL) AND
(double_col = :param2 OR :param2 IS NULL);
这一“技巧”背后的想法是,如果用户仅指定一个参数,例如:param1
,我们可以绑定null
to :param2
,以及WHERE
然后子句的行为就好像只检查第一个参数。理论上,这种方法允许我们使用单个准备好的语句来处理任意数量的输入参数,而不需要维护许多不同的语句。
我已经使用纯 JDBC 准备好的语句在本地工作了一个简单的 POC。然而,这样做需要先转换参数,然后再将其与NULL
, e.g.
WHERE (double_col = ? OR ?::numeric IS NULL)
^^ does not work without cast
然而,我的实际应用程序正在使用 JPA,并且我不断收到以下持续错误:
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: double precision = bytea
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
问题是not出现在字符串/文本列中,但仅适用于以下列:double precision
在我的 Postgres 表中。我已经尝试了所有的铸造组合,但没有任何效果:
(double_col = :param2 OR CAST(:param2 AS double precision) IS NULL);
(CAST(double_col AS double precision) = :param2 OR :param2 IS NULL);
(CAST(double_col AS double precision) = :param2 OR CAST(:param2 AS double precision) IS NULL);
该错误似乎是说 JDBC 正在向 Postgres 发送一个bytea
输入双列,然后 Postgres 会滚动,因为它找不到转换的方法byte
为双精度。
Java 代码看起来像这样:
Query query = entityManager.createNativeQuery(sqlString, MyEntity.class);
query.setParameter("param1", "some value");
// bind other parameters here
List<MyEntity> = query.getResultList();
作为参考,以下是我正在使用的所有内容的版本:
Hibernate version | 4.3.7.Final
Spring data JPA vesion | 1.7.1.RELEASE
Postgres driver version | 42.2.2
Postgres database version | 9.6.10
Java version | 1.8.0_171