【问题标题】:Date addition in postgres jpqlpostgres jpql中的日期添加
【发布时间】:2020-07-07 04:59:23
【问题描述】:

如果我像下面这样查询,我们会通过 jpql 使用 oracle db 获取数据。

public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("postgres");
    EntityManager entityManager = emf.createEntityManager();
    try {
        entityManager.getTransaction().begin();
        String jpqlQuery = "SELECT coalesce(c.actualDateTime, "
                + "coalesce("
                + "c.propDepDateTime+"
                + "TO_NUMBER(c.estOnDateTime-c.estOffDateTime),"
                + "c.estOnDateTime )) FROM Flight c  ";
        
        Query query = entityManager.createQuery(jpqlQuery);
        List<Object> objects = query.getResultList();

        objects.stream().forEach((x) -> System.out.println(x));
        entityManager.getTransaction().commit();

    } finally {

        entityManager.close();
        emf.close();
    }
}
import org.springframework.format.annotation.DateTimeFormat;
@Entity
@Table(name = "FLIGHT")
public class Flight {

    @Id
    private Long id;

    @Column(name = "ACT_DATETIME", columnDefinition = "Date")
    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "M-")
    private Date actualDateTime;

    @Column(name = "PROPAG_DEP_DATETIME", columnDefinition = "Date")
    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "M-")
    private Date propDepDateTime;

    @Column(name = "EST_ON_DATETIME", columnDefinition = "Date")
    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "M-")
    private Date estOnDateTime;

    @Column(name = "EST_OFF_DATETIME", columnDefinition = "Date")
    @Temporal(TemporalType.TIMESTAMP)
    @DateTimeFormat(style = "M-")
    private Date estOffDateTime;
DROP TABLE IF EXISTS flight;

CREATE TABLE flight(
id BIGINT PRIMARY KEY , 
ACT_DATETIME TIMESTAMP WITHOUT TIME ZONE,
PROPAG_DEP_DATETIME TIMESTAMP WITHOUT TIME ZONE,
EST_ON_DATETIME TIMESTAMP WITHOUT TIME ZONE,
EST_OFF_DATETIME TIMESTAMP WITHOUT TIME ZONE
);

INSERT INTO flight(ID,ACT_DATETIME, PROPAG_DEP_DATETIME,EST_ON_DATETIME,EST_OFF_DATETIME)
VALUES(
    1,(SELECT now()::timestamp),(SELECT now()::timestamp+1 * INTERVAL '1 DAY'),(SELECT now()::timestamp+2* INTERVAL '1 DAY'),
    (SELECT now()::timestamp+3* INTERVAL '1 DAY')
);

在迁移到 Postgres 时,我将 jpql 更改如下,但抛出 ERROR:

operator does not exist: timestamp without time zone + numeric
  Hint: No operator matches the given name and argument types. You might need to add explicit type casts.

尝试乘以区间等,但尚未奏效。欢迎任何帮助。

String jpqlQuery = "SELECT coalesce(c.actualDateTime, "
                    + "coalesce("
                    + "c.propDepDateTime+("
                    + "TO_NUMBER(quote_literal(c.estOnDateTime-c.estOffDateTime),'99999999.99999999')),"
                    + "c.estOnDateTime )) FROM Flight c  ";

【问题讨论】:

  • (SELECT now()::timestamp)可以简化为now()
  • 抱歉,无法编辑帖子。在编辑它告诉,“我的帖子是更多的代码。添加更多的细节”。对于选择我遇到问题。 Insert 在 pgadmin 中执行时工作正常。
  • 问题中无需更改,只需修复您的实际代码即可。在表达式中使用函数调用时,无需在函数调用前加上 select。你在 Oracle 中使用过values ( (select sysdate from dual), (select sysdate + 1 from dual)) 吗?
  • 在实际代码中完成

标签: postgresql jpa jpql


【解决方案1】:

如果你从另一个时间戳中减去一个时间戳,你会得到一个interval 而不是一个数字,因此将c.estOnDateTime-c.estOffDateTime 的结果传递给to_number() 也会导致错误。然后,您尝试将该号码(开头无效)添加到 timestamp,这也是不允许的。

quote_literal() 在这种情况下毫无意义。

但是您可以在时间戳中添加一个间隔,据我所知,以下应该可以满足您的要求:

coalesce(c.actualDateTime, 
         coalesce(c.propDepDateTime + (c.estOnDateTime-c.estOffDateTime),               
                  c.estOnDateTime) 
         ) 

Online example

【讨论】:

  • ``` SELECT coalesce(c.actualDateTime, coalesce(c.propDepDateTime + (c.estOnDateTime-c.estOffDateTime), c.estOnDateTime) ) FROM Flight c 抛出错误运算符不存在:时间戳没有时区 + 没有时区的时间戳 :(
  • 然后您正在运行其他东西,因为该表达式确实有效(在调整列名之后):dbfiddle.uk/… 也许您的混淆层(又名“ORM”)与代码混淆。但是 SQL 有效的
  • 天啊。在 pgadmin 中它会起作用。但我的问题是休眠执行的 jpql:|
【解决方案2】:

在自定义 PostgreDialect 中的自定义函数下方编写和注册 & 将 postgres jpql 查询中的 (c.actualDateTime-c.propDepDateTime) 更改为 to_interval(c.actualDateTime-c.propDepDateTime) 解决了这个问题。谢谢 https://stackoverflow.com/users/330315/a-horse-with-no-name|

registerFunction("to_interval", new SQLFunctionTemplate(StandardBasicTypes.TIMESTAMP, "cast(?1 as interval)"));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多