3

次の SQL クエリを使用して、月次平均を生成しています。このステートメントは頻繁に使用され、かなりうまく機能しますが、「ORA-00979: GROUP BY 式ではありません」というエラーが毎月または 2 か月に 1 回発生し、その理由はわかりません。

まずプロセスについて:

  • 数分ごとに生データがあり、
  • =>生データは、時間、日、月、および年ごとの値に平均化されています

生 -> 毎時

  • average_type 2 で averages テーブルにエントリを作成します
  • 決して問題

毎時 => 毎日 / 毎日 => 毎月 / 毎月 => 毎年

  • ステートメントはかなり似ています
  • 「より低い」タイプの平均は、より高いタイプに平均化されています
  • 平均タイプ: 2 時間ごと、3 日ごと、(4 週間は未使用) 5 か月ごと、6 年ごと

  • バグは「毎日 => 毎月」のステップでのみ表示されます。

クエリ:

  • バグを再現することはできません。通常、集計ジョブの次の実行は問題なく動作します。
  • エラーは 50 ~ 60 日ごとに発生しますが、実際のパターンはありません
  • 環境: オラクル 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
4

2 に答える 2

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, ...

...この部分で問題が解決するとは言えませんが、集約されていないという疑いから確実に取り除かれます。

于 2011-08-04T18:33:10.477 に答える
0

比較から判断すると、 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 ...
于 2011-08-05T00:44:25.730 に答える