Hibernate的Postgres Sql“无法确定参数的数据类型”

时间:2019-05-11 10:23:49

标签: sql postgresql hibernate spring-boot jpa

我有 JpaRepository

@Repository
public interface CardReaderRepository extends JpaRepository<CardReaderEntity, Integer > {


}

当我在此仓库中执行与此相同的查询时:

@Query(
    value = "SELECT new ir.server.component.panel.response." +
            "InvalidCardReaderDataDigestResponse(" +
            "    cr.driverNumber, cr.exploiterCode, cr.lineCode, " +
            "    cr.transactionDate, cr.offLoadingDate, " +
            "    cr.cardReaderNumber, " +
            "    sum(cr.count) , sum(cr.remind) " +
            ") " +
            "FROM CardReaderEntity cr " +
            "WHERE cr.company.id = :companyId " +
            "AND cr.status.id in :statusIds " +
            "AND cr.deleted = false " +
            "AND  (:fromDate is null or cr.offLoadingDate >= :fromDate ) " +
            "AND  (:toDate   is null or cr.offLoadingDate <= :toDate   ) " +
            "group by cr.driverNumber, cr.exploiterCode, cr.lineCode, cr.transactionDate, cr.offLoadingDate, cr.cardReaderNumber"
)
Page<InvalidCardReaderDataDigestResponse> findAllInvalidCardReaderDataDigestByCompanyIdAndStatusIdIn(
        @Param( "companyId" )   int companyId,
        @Param( "fromDate" )    Date fromDate,
        @Param( "toDate" )      Date toDate,
        @Param( "statusIds" )   List<Integer> statusIds,
        Pageable pageable
);

错误是:

org.postgresql.util.PSQLException: ERROR: could not determine data type of parameter $3
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2433) ~[postgresql-42.2.2.jar:42.2.2]
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2178) ~[postgresql-42.2.2.jar:42.2.2]
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306) ~[postgresql-42.2.2.jar:42.2.2]

但是当更改查询到:

@Query(
    value = "SELECT new ir.server.component.panel.response." +
            "InvalidCardReaderDataDigestResponse(" +
            "    cr.driverNumber, cr.exploiterCode, cr.lineCode, " +
            "    cr.transactionDate, cr.offLoadingDate, " +
            "    cr.cardReaderNumber, " +
            "    sum(cr.count) , sum(cr.remind) " +
            ") " +
            "FROM CardReaderEntity cr " +
            "WHERE cr.company.id = :companyId " +
            "AND cr.status.id in :statusIds " +
            "AND cr.deleted = false " +
            "AND  (:fromDate is null ) " +
            "AND  (:toDate   is null ) " +
            "group by cr.driverNumber, cr.exploiterCode, cr.lineCode, cr.transactionDate, cr.offLoadingDate, cr.cardReaderNumber"
)
Page<InvalidCardReaderDataDigestResponse> findAllInvalidCardReaderDataDigestByCompanyIdAndStatusIdIn(
        @Param( "companyId" )   int companyId,
        @Param( "fromDate" )    Date fromDate,
        @Param( "toDate" )      Date toDate,
        @Param( "statusIds" )   List<Integer> statusIds,
        Pageable pageable
);

这项工作没有错误,但希望通过 fromDate toDate

运行

注意:

CardReaderEntity 中的

卸载日期

@Basic
@Temporal( TemporalType.TIMESTAMP )
public Date getOffLoadingDate() {
    return offLoadingDate;
}
public void setOffLoadingDate(Date offLoadingDate) {
    this.offLoadingDate = offLoadingDate;
}

我的java文件中的所有Date导入都是 java.util.Date

2 个答案:

答案 0 :(得分:0)

PostgreSQL驱动程序尝试找出参数的类型,以将这些参数直接告知PostgreSQL服务器。 PostgreSQL服务器必须能够比较字段,这是必要的。如果使用java.sql.Timestamp,则PostgreSQL驱动程序将无法执行该操作,因为PostgreSQL有两个匹配的字段。一方面是时间戳,另一方面是带有时区信息的时间戳。结果是,PostgreSQL驱动程序将其与Oid.UNSPECIFIED匹配。在大多数情况下,此行为不是问题,因为PostgreSQL服务器可以检测类型。 PostgreSQL驱动程序类PgPreparedStatement中对此问题进行了详细描述。

因此,仅在Postgres无法检测到正确的类型时(当您检查null时),您才可以强制将其强制转换为时间戳/日期类型。 所以代替

(:fromDate is null )

使用

(cast(:fromDate as date) is null )

与toDate相同

答案 1 :(得分:0)

根据我的经验,必须先向外部值分配类型,然后才能要求postres检查其是否为null。例如,此代码不适用于postgres:

SELECT * FROM table WHERE $1 IS NULL OR column = $1;

可行的是:

SELECT * FROM table WHERE $1::text IS NULL OR column = $1::text;

您可以尝试将正确的类型应用于变量,以查看其是否可行。在您的示例中,您应该尝试

@Query(
    value = "SELECT new ir.server.component.panel.response." +
            "InvalidCardReaderDataDigestResponse(" +
            "    cr.driverNumber, cr.exploiterCode, cr.lineCode, " +
            "    cr.transactionDate, cr.offLoadingDate, " +
            "    cr.cardReaderNumber, " +
            "    sum(cr.count) , sum(cr.remind) " +
            ") " +
            "FROM CardReaderEntity cr " +
            "WHERE cr.company.id = :companyId " +
            "AND cr.status.id in :statusIds " +
            "AND cr.deleted = false " +
            "AND  (:fromDate::timestamp is null or cr.offLoadingDate >= :fromDate::timestamp ) " +
            "AND  (:toDate::timestamp   is null or cr.offLoadingDate <= :toDate::timestamp   ) " +
            "group by cr.driverNumber, cr.exploiterCode, cr.lineCode, cr.transactionDate, cr.offLoadingDate, cr.cardReaderNumber"
)

实际上,在大多数情况下,postgres都不会要求输入类型,检查null值是必须使用类型的特殊情况之一。