【问题标题】:select records expiring within the next 30 days - sql statement选择未来 30 天内到期的记录 - sql 语句
【发布时间】:2019-02-05 16:38:11
【问题描述】:

数据类型:timestamp 列名:dlExpiryDate

SELECT * 
  FROM QUALIFICATION  
 WHERE dlExpiryDate >= NOW() 
   AND dlExpiryDate < NOW() + INTERVAL 1 MONTH;

尝试了许多查询以获得答案,但它不起作用。任何人都得到了解决这个问题的答案。有一个我在上面尝试过的例子,但它不起作用。 打印出堆栈跟踪:

严重:java.sql.SQLSyntaxErrorException:语法错误:遇到 第 1 行第 93 列的“1”。 org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(未知 来源)在 org.apache.derby.client.am.SqlException.getSQLException(未知 来源)在 org.apache.derby.client.am.Statement.executeQuery(未知 来源)在 org.apache.jsp.viewQualification_jsp._jspService(viewQualification_jsp.java:105) 在 org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:111) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:790) 在 org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:411) 在 org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:473) 在 org.apache.jasper.servlet.JspServlet.service(JspServlet.java:377) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:790) 在 org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160) 在 org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734) 在 org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673) 在 com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174) 在 org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:416) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:283) 在 com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459) 在 com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167) 在 org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206) 在 org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180) 在 org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235) 在 org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) 在 org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:283) 在 org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200) 在 org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132) 在 org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111) 在 org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) 在 org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536) 在 org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112) 在 org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117) 在 org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56) 在 org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137) 在 org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591) 在 org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571) 在 java.lang.Thread.run(Thread.java:745) 引起: org.apache.derby.client.am.SqlException:语法错误:遇到“1” 在第 1 行,第 93 列。 org.apache.derby.client.am.Statement.completeSqlca(Unknown Source) at org.apache.derby.client.net.NetStatementReply.parsePrepareError(未知 来源)在 org.apache.derby.client.net.NetStatementReply.parsePRPSQLSTTreply(未知 来源)在 org.apache.derby.client.net.NetStatementReply.readPrepareDescribeOutput(未知 来源)在 org.apache.derby.client.net.StatementReply.readPrepareDescribeOutput(未知 来源)在 org.apache.derby.client.net.NetStatement.readPrepareDescribeOutput_(未知 来源)在 org.apache.derby.client.am.Statement.readPrepareDescribeOutput(未知 来源)在 org.apache.derby.client.am.Statement.flowExecute(未知 来源)在 org.apache.derby.client.am.Statement.executeQueryX(未知 来源)... 36 更多

请问有人回答了吗?谢谢

【问题讨论】:

  • Stacktrace 清楚地表明您使用的是 Derby,而不是 MySQL,所以不要再尝试使用 MySQL 语法了!

标签: java date derby


【解决方案1】:

时区

请注意,Derby 中的 TIMESTAMP 类型类似于 SQL 标准类型 TIMESTAMP WITHOUT TIME ZONE(至少看起来是这样,文档写得不好)。意思是,该类型缺少time zone 或offset-from-UTC 的任何概念。因此,这种类型 不 表示特定时刻,即时间轴上的一个点。相反,它代表大约 26-27 小时范围内的潜在时刻,即全球时区范围。

例如,如果您存储的时间是 2019 年 1 月 23 日中午,我们不知道您是指日本东京的中午,还是印度加尔各答中午之前的几个小时。或者你的意思是几个小时后,法国巴黎的中午。或者再过几个小时,当中午到达魁北克蒙特利尔时。这种类型的值意味着 23 日中午任何地方,在 26-27 小时范围内的许多时刻中的任何一个。

因此,与现在、当前时刻相比,对这种类型进行查询毫无意义。

但是……

如果您一直在处理应用程序中的时区,并假设数据库中的所有值都属于某个时区,则在捕获当前时刻时使用该时区。

ZonedDateTime

在 java.time 类中,我们使用ZonedDateTime 表示特定地区(时区)的人们使用的挂钟时间中的时刻。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Capture the current moment as seen in the wall-clock time used by the people of a particular region (a time zone).

用LocalDateTime 丢弃有价值的区域/偏移信息

我们可以去掉时区信息,在 LocalDateTime 对象中只留下日期和时间。

LocalDateTime ldt = zdt.toLocalDateTime()

一天的开始

如果搜索一个月,您可能希望从一天的开始开始。暂时,我们会让 java.time 确定一天的第一时刻,因为由于夏令时 (DST) 等异常情况,一天并不总是从 00:00 开始。但是由于LocalDateTime 缺少区域/偏移量,我们无法解释此类异常。所以我们会选择 00:00。

LocalDateTime ldtStartOfDay = ldt.with( LocalTime.MIN ) ;

日期时间数学

要添加您的月份,我们可以使用 plus… 和 minus… 方法进行日期时间数学运算。

LocalDateTime ldtMonthLater = ldtStartOfDay.plusMonths() ;

SQL 占位符

传递这些值以在准备好的语句中替换 SQL 中的占位符。

SELECT * 
FROM QUALIFICATION  
WHERE dlExpiryDate >= ?
AND dlExpiryDate < ?
;

JDBC 4.2

从 JDBC 4.2 及更高版本开始,我们可以使用 setObject 和 getObject 直接与数据库交换 java.time 对象。无需使用诸如java.sql.Timestamp 之类的可怕遗留类。

myPreparedStatement.setObject( 1 , ldtStartOfDay) ;
myPreparedStatement.setObject( 2 , ldtMonthLater) ;

检索时。

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

考虑其他数据库

您可能要考虑使用其他数据库。 Oracle 停止将 Derby 捆绑为 Java DB,因为发现它不适合生产使用。

如果您想要一个用 Java 编写的开源数据库,我建议您使用 H2 Database Engine,它既适合嵌入式使用,也适合服务器使用。如果你想要一个为重型企业质量工作而构建的开源数据库服务器,我建议Postgres。


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。

【讨论】:

    【解决方案2】:

    如果您想以与数据库无关的方式执行该查询,请在 Java 代码中解析这两个日期并使用 PreparedStatement 提供它们。

    LocalDate today = LocalDate.now();
    String sql = "SELECT *" +
                  " FROM QUALIFICATION" +
                 " WHERE dlExpiryDate >= ?" +
                   " AND dlExpiryDate < ?";
    try (PreparedStatement stmt = conn.prepareStatement(sql)) {
        stmt.setDate(1, java.sql.Date.valueOf(today));
        stmt.setDate(2, java.sql.Date.valueOf(today.plusMonths(1)));
        try (ResultSet rs = stmt.executeQuery()) {
            // code here
        }
    }
    

    根据 JDBC 驱动程序(例如不是 Microsoft),您也可以使用 setObject。

    stmt.setObject(1, today);
    stmt.setObject(2, today.plusMonths(1));
    

    【讨论】:

    • 考虑到列是时间戳,这仍然有效吗?
    • @unknown 如果您希望将时间包含在边界中,请改用LocalDateTime 和java.sql.Timestamp。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-24
    • 2011-04-21
    • 2013-12-29
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多