首页 > 解决方案 > 使 oracle last_day 函数在 oracle 和 h2 之间兼容

问题描述

我在 java 项目中有一个 sql 查询。它必须在 oracle 和 h2 中执行,具体取决于客户端和 DBMS 选举。

它必须返回 sent_date 是 Month 减一的值(上个月的注册表)

SELECT * FROM TABLE WHERE SENT_DATE BETWEEN ADD_MONTHS(TRUNC(SYSDATE,'mm'),-1) 
AND LAST_DAY(ADD_MONTHS(TRUNC(SYSDATE,'mm'),-1)) ORDER BY ELAPSED_TIME DESC

问题是,LAST_DAY 函数是 Oracle 特定的函数,在 H2 中不存在,H2 日期管理有时在 Oracle 中不起作用,但我需要它完全兼容。之前有一个问题Make Oracle last_day function be compatible with H2 database但答案集中在测试不佳的系统上,而不是正确的解决方案上。

我们怎样才能做到这一点?

标签: javaoracleh2

解决方案


它可能会更快乐:

SELECT * FROM TABLE
WHERE SENT_DATE BETWEEN ADD_MONTHS(TRUNC(SYSDATE,'mm'),-1) AND TRUNC(SYSDATE,'mm') - 1
ORDER BY ELAPSED_TIME DESC

表明它们评估为相同的值:

SELECT ADD_MONTHS(TRUNC(SYSDATE,'mm'),-1) as orig_start,
  LAST_DAY(ADD_MONTHS(TRUNC(SYSDATE,'mm'),-1)) as orig_end,
  TRUNC(SYSDATE,'mm') - 1 as new_end
FROM dual;

ORIG_START          ORIG_END            NEW_END            
------------------- ------------------- -------------------
2019-08-01 00:00:00 2019-08-31 00:00:00 2019-08-31 00:00:00

但请记住,这between是包容性的,因此如果您sent_date有非午夜时间,则将排除从 2019-08-31 00:00:01 到 2019-08-31 23:59:59 的任何时间。

这样做更安全:

SELECT * FROM TABLE
WHERE SENT_DATE >= ADD_MONTHS(TRUNC(SYSDATE,'mm'),-1)
AND SENT_DATE < TRUNC(SYSDATE,'mm')
ORDER BY ELAPSED_TIME DESC

这将包括 2019-08-01 00:00:00 或之后的所有内容,直到(但不包括)2019-09-01 00:00:00 - 这样就不会出现丢失的日期。

或者,如果它不能识别add_months

SELECT * FROM TABLE
WHERE SENT_DATE >= TRUNC(SYSDATE,'mm') - INTERVAL '1' MONTH
AND SENT_DATE < TRUNC(SYSDATE,'mm')
ORDER BY ELAPSED_TIME DESC

(我无法测试这些中的任何一个是否真的在 H2 中工作...... *8-)


推荐阅读