【问题标题】:Strange periodic group by problems (ORA-00979)奇怪的周期性群问题 (ORA-00979)
【发布时间】:2011-10-20 05:12:24
【问题描述】:

我们使用以下 SQL 查询来生成每月平均值。该语句被大量使用并且运行良好,但它每两个月都会出现 'ORA-00979: not a GROUP BY expression' 失败,我们不知道为什么.

先说流程:

  • 我们每隔几分钟就有一次原始数据,
  • => 原始数据被平均为每小时、每天、每月和每年的值

原始 -> 每小时

  • 在 average_type 2 的平均值表中创建条目
  • 从来没有问题

每小时 => 每天 / 每天 => 每月 / 每月 => 每年

  • 语句非常相似
  • “较低”类型的平均值正在被平均到较高类型
  • 平均类型为:2 小时、3 天、(4 周未使用)5 月和 6 年

  • 该错误仅出现在“每日 => 每月”这一步。

查询:

  • 我们无法重现该错误,聚合作业的下一次运行通常不会出现问题。
  • 错误每 50-60 天发生一次,没有真正的规律
  • 环境:Oracle 10g

有人知道问题可能是什么吗?

INSERT INTO averages
SELECT averages_seq.NEXTVAL,
       avg.*
FROM (
  SELECT
      m.city_id,            m.city_name,
      m.state_id,           m.state_name,
      m.district_id,        m.district_name,
      m.country_id,         m.country_name,
      m.currency_id,        m.currency_name,
      m.category_id,        m.category_name,
      5 average_type, -- average_type 5 ==> monthly average
      0 analysis_type,
      TRUNC(m.average_date, 'MM')  average_date,
      AVG(m.value) value,
      SUM(m.sum) sum,
      NULL uncertainty,
      NULL uncertainty_type,
      MIN(m.value_min) value_min,
      MAX(m.value_max) value_max,
      SUM(number_of_measurements) number_of_measurements,
      -- 6 * 24 => measurements per day
      -- (ADD_MONTHS(...)) => days per month 
      100 * SUM(number_of_measurements) / 
           (6 * 24 *
           (ADD_MONTHS(TRUNC(average_date, 'MM'), 1)  - TRUNC(average_date, 'MM'))) coverage_percent,
      SUM(customers) customers,
      NULL dummy_field,
      CURRENT_TIMESTAMP calculation_date,
      CURRENT_TIMESTAMP creation_date,
      'AGGREGATION' creation_user,
      CURRENT_TIMESTAMP modification_date,
      'AGGREGATION' modification_user,
      'n' constant_1,
      3   constant_2,
      -1 average_state
  FROM averages m
  WHERE   m.average_type = 3 -- average type 3 ==> daily average
  AND     m.average_date
      BETWEEN
        TO_TIMESTAMP('2011-06-01T00:00:00Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
        AND
        TO_TIMESTAMP('2011-06-30T23:59:59Z', 'YYYY-MM-DD"T"HH24:MI:SS"Z"')
  AND     m.analysis_type = 0
  GROUP BY
        m.city_id,            m.city_name,
        m.state_id,           m.state_name,
        m.district_id,        m.district_name,
        m.country_id,         m.country_name,
        m.currency_id,        m.currency_name,
        m.category_id,        m.category_name,
        TRUNC(m.average_date, 'MM')
  ) avg

【问题讨论】:

  • 我删除了我的答案,因为文档说 sysdate 在单个 SQL 语句上下文 (oracle.su/docs/11g/timesten.112/e13070/ttsql247.htm) 中总是返回相同的 DATE 值。
  • 我想知道是否存在 GROUP BY 部分中的列之一可能为空的情况。这是我唯一能想到的。
  • @Gerrat:感谢您的想法,甚至更感谢您检查它不可能是问题:)!纳尼安:我不确定 null 怎么会有问题?
  • @reto/@Narnian...我怀疑 null 可能是个问题...您可以按包含 null 的列进行分组(它只是一个单独的组)
  • 关于 ORA-00979 错误(或者更确切地说是 GROUP BY 表达式)的有趣之处在于,如果它们是 PL/SQL 过程的一部分,则在编译时而不是在运行时检查它们. (试试 SELECT A, B FROM T GROUP BY A)。 NULL、日期或任何表内容几乎不是问题,因为正确性仅取决于表定义。看起来好像是 Oracle 错误,或者您的 AGGREGATES 表在查询运行之间发生了更改 (DDL)。您是否正在重建索引、添加或删除分区、启用或禁用约束?

标签: sql oracle group-by ora-00979


【解决方案1】:

我会通过以下方式添加一个组:

(ADD_MONTHS(TRUNC(average_date, 'MM'), 1)  - TRUNC(average_date, 'MM'))

我知道如果不更改 TRUNC(m.average_date, 'MM'),这将无法更改,但它似乎是唯一不在您的 GROUP BY 中的非聚合列。

此外,您可以删除内部 sql 之外的所有非聚合的常量列,并显式命名您要插入的列并同时选择这些常量:

例如。

INSERT INTO averages(city_id, city_name, ...average_type, analysis_type, ...)
SELECT averages_seq.NEXTVAL,
avg.city_id, avg.city_name, ...
5, 0, ...

...不能说这部分会解决问题,但肯定会消除他们没有被聚合的嫌疑。

【讨论】:

  • 如果我能重现这个问题,这将是一个明智的选择。但如果没有其他问题,我会尝试!
  • 我不明白为什么这个答案会被赞成。如果TRUNC(average_date, 'MM') 是按表达式分组,则所有表达式都基于它构建,而不引入任何新的非聚合或非分组列。建议的解决方案不仅仅是猜测(有时需要找到错误),它们违反了 SQL 的 GROUP BY 子句的逻辑。
  • 我将所有非聚合部分移出内部查询。我们会看看它是否能修复它。
  • 到目前为止错误没有再次出现。将所有非聚合内容移至外部查询会有所帮助。感谢您的帮助!
  • 好的,现在很清楚,查询重写解决了'ORA-00979',错误没有再次出现。
【解决方案2】:

从比较来看,average_date 是一个带有时区(本地时区?)的时间戳,但 TRUNC 在日期上工作。我想知道如果出现一些奇怪的情况,即所选日期从一个月“跳跃”到另一个(例如,它发生在一个时区的 1 月,而另一个时区的 2 月)。

在此基础上,还要考虑客户端是否有影响,(例如,从与数据库设置不同时区的客户端运行时可能会出错)。

我会扩展 Gerrat 关于指定列名的建议,以便您可以分离出常量

INSERT INTO averages
  (average_type, analysis_type, uncertainty, uncertainty_type,
  dummy_field, calculation_date, creation_date, creation_user, 
  modification_date, modification_user, constant_1, constant_2,
   ....
SELECT averages_seq.NEXTVAL,
      5 average_type, -- average_type 5 ==> monthly average
      0 analysis_type,
      NULL uncertainty,
      NULL uncertainty_type,
      NULL dummy_field,
      CURRENT_TIMESTAMP calculation_date,
      CURRENT_TIMESTAMP creation_date,
      'AGGREGATION' creation_user,
      CURRENT_TIMESTAMP modification_date,
      'AGGREGATION' modification_user,
      'n' constant_1,
      3   constant_2,
      -1 average_state
       avg.*
FROM (
  SELECT ...

【讨论】:

  • 所有数据都是UTC。只有一个客户端正确设置时区。重新运行时,该作业可以正常工作。感谢您的想法!
猜你喜欢
  • 2016-08-25
  • 1970-01-01
  • 2014-03-24
  • 2011-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多