按年份和月份筛选记录,其中年份和月份是表格中的列

时间:2014-05-13 09:21:43

标签: sql oracle

所以我有这个特定的表结构

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来构建一个查询来获得正确的年份,但我无法解决选择月份范围的逻辑问题。

4 个答案:

答案 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;

需要注意的一些遗留问题:

  1. x BETWEEN y z 的标准行为要求 y 小于或等于< EM>ž。也就是说,x BETWEEN y AND z相当于x >= y AND x <= z。 (有没有DBMS将其视为等同于x >= MIN(y, z) AND z <= MAX(y, z)?)因此上面的代码切换-12和-24,因此范围是正确的。
  2. x BETWEEN y z 的界限是包含的,因此-24到-12范围涵盖13个月,而不是12个月。只要这是你想要的,那就没事了。否则,你可能需要-24 ..- 13或者-23 ..- 12。
  3. 您可以使用函数YEAR()MONTH()代替ExtractYear()ExtractMonth()。您可能需要担心列名YearMonth与同名函数之间的歧义。这是否重要将取决于DBMS。
  4. 这个问题确实强调日期算术是棘手的东西,从日期减去几个月时,总是要记住闰年和月末。例如,什么日期对应于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