所以我有这个特定的表结构
State_Code | ColA | ColB | Year | Month
---------- ------ ---- ------ -----
AK 5 3 2013 4
AK 6 1 2014 8
AK 3 4 2012 9
.
.
.
.
.
我无权更改表格结构。 所需的查询描述如下
查找过去12个月和过去24个月之间每个州的总ColA,ColB。
问题 是否可以在不使用存储过程的情况下完成此类查询。 我可以使用add_months来构建一个查询来获得正确的年份,但我无法解决选择月份范围的逻辑问题。
答案 0 :(得分:6)
社区Wiki,因为它从其他答案中大量借用。
answer Farhad Jabiyev(现已删除 - 请参阅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
相当于x >= y AND x <= z
。 (有没有DBMS将其视为等同于x >= MIN(y, z) AND z <= MAX(y, z)
?)因此上面的代码切换-12和-24,因此范围是正确的。YEAR()
和MONTH()
代替ExtractYear()
和ExtractMonth()
。您可能需要担心列名Year
和Month
与同名函数之间的歧义。这是否重要将取决于DBMS。 这个问题确实强调日期算术是棘手的东西,从日期减去几个月时,总是要记住闰年和月末。例如,什么日期对应于2014-04-29,2014-04-30,2014-08-31,2016-04-29,2016-04-30之前的2个月?
警告:未经测试的SQL:可能出现语法错误。
答案 1 :(得分:2)
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;
答案 2 :(得分:2)
作为一个说明,我发现最简单的方法是不使用日期。只需将年月表达式转换为YYYYMM格式的数字即可。例如,2014年5月变为201405.我还将使用条件聚合来获取包含历史摘要的两列:
select state_code,
sum(case when year * 100 + month > (year(sysdate) - 1) * 100 + month(sysdate) and
year * 100 + month <= year(sysdate) * 100 + month(sysdate)
then colA + colB else 0
end) as AB_12,
sum(case when year * 100 + month > (year(sysdate) - 2) * 100 + month(sysdate) and
year * 100 + month <= year(sysdate) * 100 + month(sysdate)
then colA + colB else 0
end) as AB_24
from table t
group by state_code;
答案 3 :(得分:0)
select t.state_code, sum(t.cola) total_cola, sum(t.colb) total_colb
from your_table t
where to_date(t.year || lpad(t.month, 2, '0'), 'yyyymm')
between add_months(sysdate, -12)
and add_months(sysdate, -24)
group by t.state_code