PostgreSQL查询传入Timestamp参数报date_part函数不唯一错误
问题描述
在PostgreSQL查询中使用java.sql.Timestamp类型变量作为传参执行SQL时,触发如下报错:
bad SQL grammar [select extract(year from LOCALTIMESTAMP) -extract(year from ?)]; nested exception is org.postgresql.util.PSQLException: ERROR: function pg_catalog.date_part(unknown, unknown) is not unique
对应实现代码如下,两种传参写法(直接传入dt对象、显式指定Types.TIMESTAMP类型传参)均无法正常执行,都会触发上述报错:
private void myFN(Timestamp dt) { rowSet = jdbcTemplate.queryForRowSet("select extract(year from LOCALTIMESTAMP) -extract(year from ?)", dt); rowSet = jdbcTemplate.queryForRowSet("select extract(year from LOCALTIMESTAMP) -extract(year from ?)", new Object[] { dt }, new int[] { Types.TIMESTAMP }); }
报错根因
extract(field from source)是PostgreSQL对date_part(field, source)函数封装的语法糖。预编译SQL执行时,PostgreSQL服务端在解析?占位符的阶段,无法自动推导占位符对应的明确数据类型;即使JDBC客户端已经声明参数类型为Types.TIMESTAMP,服务端的函数签名匹配阶段仍会将该占位符判定为unknown类型,最终无法匹配到合法的date_part函数签名,抛出函数不唯一的错误。
修复方案
在SQL语句中对传入的占位符做显式类型强转,强制指定参数为时间类型即可,不需要修改Java端的传参逻辑,修改后的SQL写法如下:
-- 转换为无时区时间戳 select extract(year from LOCALTIMESTAMP) - extract(year from ?::timestamp)
如果业务场景传入的是带时区的时间戳,也可以根据实际需求转换为带时区的时间戳类型:
-- 转换为带时区时间戳 select extract(year from LOCALTIMESTAMP) - extract(year from ?::timestamptz)
内容的提问来源于stack exchange,提问作者Леонид
相关产品推荐
相关产品推荐

