简体   繁体   English

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

[英]Postgres Sql `could not determine data type of parameter` by Hibernate

I have JpaRepository :我有JpaRepository

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


}

when i execute query in this repo same as this:当我在此 repo 中执行与此相同的查询时:

@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
);

error is:错误是:

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]

but when a change query to:但是当将查询更改为:

@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
);

this work without error but a want run with fromDate and toDate这项工作没有错误,但希望使用fromDatetoDate运行

note:笔记:

offLoadingDate in CardReaderEntity : CardReaderEntity中的offLoadingDate

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

all of Date import in my java files is java.util.Date .我的 java 文件中的所有 Date 导入都是java.util.Date

The PostgreSQL driver tries to figure out the type of the parameters to tell those parameters directly to the PostgreSQL Server. PostgreSQL 驱动程序试图找出参数的类型,以将这些参数直接告诉 PostgreSQL 服务器。 This is necessary that the PostgreSQL server is able to compare fields.这是 PostgreSQL 服务器能够比较字段所必需的。 In case of a java.sql.Timestamp the PostgreSQL driver is just not able to do it since there are two matching fields for PostgreSQL.在 java.sql.Timestamp 的情况下,PostgreSQL 驱动程序无法执行此操作,因为 PostgreSQL 有两个匹配字段。 On the one side, there is the timestamp and on the other side the timestamptz with timezone information.一方面是时间戳,另一方面是带有时区信息的时间戳。 The result is, that the PostgreSQL driver will just match it to Oid.UNSPECIFIED.结果是,PostgreSQL 驱动程序只会将它与 Oid.UNSPECIFIED 匹配。 This behavior is most of the time not an issue since the PostgreSQL server is able to detect the type.这种行为在大多数情况下不是问题,因为 PostgreSQL 服务器能够检测到类型。 There is a detailed description of this issue in the PostgreSQL driver class PgPreparedStatement. PostgreSQL 驱动类 PgPreparedStatement 中有对这个问题的详细描述。

So what you can do is force cast to timestamp/date type only when Postgres is not able to detect proper type (when you are checking for null).因此,您可以做的是仅当 Postgres 无法检测到正确的类型(当您检查 null 时)时才强制转换为时间戳/日期类型。 So instead of所以代替

(:fromDate is null )

use

(cast(:fromDate as date) is null )

same for toDate相同的 toDate

By my experience, you must assign a type to the outer value before you can ask postres to check whether it is null or not.根据我的经验,您必须先为外部值分配一个类型,然后才能要求 postres 检查它是否为 null。 For example, this code won't work for postgres:例如,此代码不适用于 postgres:

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

And what would work is:什么是有效的:

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

You can try applying the correct type to your variables to see if it works out.您可以尝试将正确的类型应用于您的变量,看看它是否有效。 In your example, you should try在您的示例中,您应该尝试

@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"
)

In fact, postgres won't ask for types in most of the cases, checking null value is one of the special cases that type becomes necessary.事实上,postgres 在大多数情况下不会要求类型,检查空值是类型变得必要的特殊情况之一。

Add casting only when comparing to null and not when actual data comparison occurs.仅在与 null 进行比较时添加转换,而不是在发生实际数据比较时添加。

    @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  (cast(:fromDate as timestamp) is null or cr.offLoadingDate >= :fromDate ) " +
            "AND  (cast(:toDate as timestamp)   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
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM