社区 Wiki,因为它大量借鉴了其他答案。
Farhad Jabiyev 的 answer(现已删除 - 请参阅 Is it OK to unaccept an accepted answer after weeks)是:
SELECT STATE_CODE, SUM(COLA) SUM_COLA, SUM(COLB) SUM_COLB
FROM TABLE_NAME
WHERE to_date(ExtractDay(sysdate) || MONTH || YEAR, 'ddMMyyyy')
between add_months(sysdate,-12) AND add_months(sysdate,-24)
GROUP BY STATE_CODE;
当当前日期在某些时间间隔的月底(-24..-12 个月范围,通常仅在闰日,但对于其他月份范围,它可以)时,此答案会遇到问题从本月 29 日开始遇到问题)。
但是,它坚定地走在正确的轨道上,只需要(相对)微不足道的修复。要求是得到当月减去12个月和当月减去24个月的年/月组合。
- 将“日期”从
ExtractDay(sysdate) 更改为每月的 '01'(因为存储的数据只有一个月粒度,每个月都有一个月的第一天,但不是每个月都有 29 日、30 日或31 日)。
如果使用日期,则需要获取当前月份的第一天(两次),这是详细的:
SELECT STATE_CODE, SUM(COLA) SUM_COLA, SUM(COLB) SUM_COLB
FROM TABLE_NAME
WHERE to_date('01' || MONTH || YEAR, 'ddMMyyyy')
BETWEEN to_date('01' || ExtractMonth(add_months(sysdate, -24)) ||
ExtractYear(add_months(sysdate, -24)), 'ddMMyyyy')
AND to_date('01' || ExtractMonth(add_months(sysdate, -12)) ||
ExtractYear(add_months(sysdate, -12)), 'ddMMyyyy')
GROUP BY STATE_CODE;
另外,可能更好(如果只是因为更简单)是按照Gordon Linoff 在他的answer 中的建议转换年/月组合:
SELECT STATE_CODE, SUM(COLA) SUM_COLA, SUM(COLB) SUM_COLB
FROM TABLE_NAME
WHERE (MONTH + 100 * YEAR)
BETWEEN (ExtractMonth(add_months(sysdate, -24)) + 100 *
ExtractYear(add_months(sysdate, -24)))
AND (ExtractMonth(add_months(sysdate, -12)) + 100 *
ExtractYear(add_months(sysdate, -12))
GROUP BY STATE_CODE;
需要注意的一些遗留问题:
-
x BETWEEN y AND z 的标准行为要求 y 小于或等于 z。也就是说,
x BETWEEN y AND z 等价于 x >= y AND x <= z。 (是否有任何 DBMS 将其视为等同于 x >= MIN(y, z) AND z <= MAX(y, z)?)因此上面的代码切换 -12 和 -24,因此范围是正确的。
-
x BETWEEN y AND z 的范围包括在内,因此 -24 到 -12 的范围涵盖 13 个月,而不是 12 个月.只要这是你想要的,没问题。否则,您可能需要 -24..-13 或 -23..-12。
- 您可以使用函数
YEAR() 和MONTH() 代替ExtractYear() 和ExtractMonth()。您可能需要担心列名 Year 和 Month 与同名函数之间的歧义。这是否重要取决于 DBMS。
这个问题确实强调了日期算术是一个棘手的问题,从日期中减去月份时,必须始终牢记闰年和月末。例如,2014-04-29、2014-04-30、2014-08-31、2016-04-29、2016-04-30 前 2 个月对应的日期是什么?
警告:未经测试的 SQL:可能存在语法错误。