按月查找值的总和然后找到最大的月数总和

find sum of values by month then find max sum of months

我需要找到每个月的值总和,然后找到月份的最大值。我有点难过,不知道该怎么办。

My customer wants it formatted a particular way:

Activity |  JUN  |  JUL  |  AUG  |  MIN  |   MAX  |  AVG
jogging  |  232  |   32  |  343  |   32  |   343  |  202 

Here is my table:

activity + status + date
____________________________
swimming +    1   + 13-DEC-02
swimming +    1   + 12-FEB-01
jogging  +    0   + 14-AUG-03

这是我目前的情况:

SELECT ACTIVITY,
  SUM(
  CASE
    WHEN DECODE(TO_CHAR((TRUNC(date)), 'MON'),'JUL','JUL') IN 'JUL'
    THEN 1
    ELSE 0
  END ) JUL,
  SUM(
  CASE
    WHEN DECODE(TO_CHAR((TRUNC(date)), 'MON'),'AUG','AUG') IN 'AUG'
    THEN 1
    ELSE 0
  END ) AUG
FROM daily_log
WHERE ACTIVITY_DESC IN ('Swimming','Jogging')
AND TRUNC(date) BETWEEN '01-JUL-2014' AND '30-JUN-2015'
AND STATUS = 1
group by ACTIVITY

求助!

对于 MIN/MAX,您可以使用 GREATEST 和 LEAST,如果您只需要 result.O 中的 select 值,则可以使用 MIN、MAX 和 AVG 函数来聚合这些值直接来自源数据。

http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions001.htm

您可能还想研究使用子查询,尤其是使用 WITH 子句。您可以将 select 个中间结果组合在一起。

http://oracle-base.com/articles/misc/with-clause.php

关于 SUM(CASE 位,您可以访问 PIVOT 作为将行转换为列的选项。

http://oracle-base.com/articles/11g/pivot-and-unpivot-operators-11gr1.php

编辑: 应该这样做

SELECT Activity,
  COALESCE(AUG,0) AS AUG,
  COALESCE(JUN,0) AS JUN,
  COALESCE(JUL,0) AS JUL,
  MIN,MAX,AVG
FROM (
    SELECT
      Mon,
      Activity,
      Count, 
      MIN(Count) OVER (PARTITION BY Activity) AS Min,
      MAX(Count) OVER (PARTITION BY Activity) AS Max,
      AVG(Count) OVER (PARTITION BY Activity) AS Avg
    FROM (
      SELECT TO_CHAR("date",'MON') AS Mon, activity, COUNT(*) Count
      FROM daily_log
      GROUP BY TO_CHAR("date",'MON'), activity
    )
) PIVOT ( SUM(Count) FOR Mon IN ('AUG' AS AUG, 'JUN' AS JUN, 'JUL' AS JUL))

您的查询有点太复杂了。例如:

CASE
    WHEN DECODE(TO_CHAR((TRUNC(date)), 'MON'),'AUG','AUG') IN 'AUG'
    THEN 1
    ELSE 0
END

可以重写为:

CASE WHEN TO_CHAR(date, 'MON') = 'AUG' THEN 1 ELSE 0 END

甚至:

DECODE(TO_CHAR(date, 'MON'), 'AUG', 1, 0)

换句话说,您需要 CASEDECODE(),但不能同时需要两者。考虑到这一点,我们可以稍微重写您的查询:

SELECT activity
     , SUM(DECODE(TO_CHAR(date, 'MON'), 'JUL', 1, 0)) AS jul
     , SUM(DECODE(TO_CHAR(date, 'MON'), 'AUG', 1, 0)) AS aug
  FROM daily_log
 WHERE activity_desc IN ('Swimming','Jogging')
   AND date >= DATE'2014-07-01'
   AND date < DATE'2015-07-01'
   AND status = 1
GROUP BY activity;

现在,请注意我是如何更改 date 列上的过滤器的(顺便说一下,这是一个糟糕的列名称,因为 DATE 是一个 Oracle 关键字,用于数据类型和 ANSI 日期文字)。您希望避免在 DATE 列上使用 TRUNC(),尤其是在它已被索引时(如果未被索引,您可能需要考虑对其进行索引)。由于您需要所有月份的最小值和最大值,因此您需要使用 LEAST()GREATEST() 函数:

SELECT activity, jul, aug
     , LEAST(jul, aug) AS min
     , GREATEST(jul, aug) AS max
     , (jul+aug)/2 AS avg
  FROM (
    SELECT activity
         , SUM(DECODE(TO_CHAR(date, 'MON'), 'JUL', 1, 0)) AS jul
         , SUM(DECODE(TO_CHAR(date, 'MON'), 'AUG', 1, 0)) AS aug
      FROM daily_log
     WHERE activity_desc IN ('Swimming','Jogging')
       AND date >= DATE'2014-07-01'
       AND date < DATE'2015-07-01'
       AND status = 1
    GROUP BY activity
);

不幸的是,LEAST()GREATEST() 无法计算平均值,因此我们必须手动计算。添加额外月份的结果时,您需要增加分母。

您想要聚合两次:一次计算每月汇总,第二次计算这些汇总的统计信息。这需要(至少)两个查询,一个在另一个范围内作为公共 table 表达式、内联视图或子查询。例如:

SELECT
  activity,
  SUM(
    CASE month
      WHEN 7 THEN count
      ELSE 0
    END
  ) JUL,
  SUM(
    CASE month
      WHEN 8 THEN count
      ELSE 0
    END
  ) AUG,
  AVG(count) AS avg,
  MAX(count) AS max
FROM (
  SELECT
    activity,
    EXTRACT(MONTH FROM "date") AS month,
    COUNT(*) AS count
  FROM daily_log
  WHERE
    ACTIVITY_DESC IN ('Swimming','Jogging')
    AND TRUNC("date") BETWEEN '01-JUL-2014' AND '30-JUN-2015'
    AND STATUS = 1
  group by ACTIVITY, EXTRACT(MONTH FROM "date")
)
GROUP BY activity

请注意,在您的 真实 查询中,您可能希望比 AVG(count) 更聪明,否则如果平均值为零,您将得到错误的平均值一个或多个月内感兴趣的条目。