データベース

【解決】ORA-00979: GROUP BYの式ではありません。

  • このエントリーをはてなブックマークに追加
  • LINEで送る

Oracleで”GROUP BY”の使い方を間違うと…

「ORA-00979: GROUP BYの式ではありません」

というエラーが発生します。

『何だコレ?』

って思うカモですが、すぐに解決できます!

サクっと解決して、ササっと帰宅してダラダラしましょう^^

 

『ORA-00979のエラー原因はなんだろう…』

『どうやってエラーを解消するんだろう…』

 

このような疑問に答えます。


【原因と解決策】ORA-00979: GROUP BYの式ではありません

まず、結論から!

「ORA-00979: GROUP BYの式ではありません」

このエラー原因と4つの解決方法について述べます。

原因

GROUP BYに存在しない項目をSELECTしてるため

解決方法(4パターン)
  1. GROUP BYにSELECTしたい項目を追加する
  2. GROUP BYをやめてDISTINCTを指定する
  3. SELECTしたい項目に集約関数を使用する
  4. 分析関数を使用する
SEおっさん
SEおっさん
もうちょい、詳しく説明するぞい!


スポンサーリンク

原因:ORA-00979: GROUP BYの式ではありません。

『ORA-00979: GROUP BYの式ではありません。』

原因は…

GROUP BY句を使用した場合、
SELECT項目はGROUP BYで指定してない項目を使用できない

という決まりがあるからです。

エラー例【ORA-00979: GROUP BYの式ではありません】

ORA-00979が発生するSELECT文の実行例です。

性別は男女、数学は点数だとします。

SELECT
    性別, 数学
FROM クラス
GROUP BY 性別;
ORA-00979: GROUP BYの式ではありません。
00979. 00000 -  "not a GROUP BY expression"

性別と数学をSELECTしてますが、数学がGROUP BYに存在しないのでエラーとなります。

エラー内容が「GROUP BYに項目が存在しません」だったらわかりやすいですけどね ^^;

SEおっさん
SEおっさん
SE20年のオッサンでも、この間違いはやってしまいそうになります。
注意してね!

解消法4つ:ORA-00979: GROUP BYの式ではありません。

『ORA-00979: GROUP BYの式ではありません。』

の解消法を4つご紹介します。

データ取得する目的に合った解消法を選んでみましょう!

解消法(その1):GROUP BYにSELECTしたい項目を追加する

GROUP BY句にSELECTしたい項目を追加します。

最もシンプルな解消法です。

例)GROUP BY句に項目「数学」を追加してエラーを解消

SELECT
    性別, 数学
FROM クラス
GROUP BY 性別, 数学;
-+--------+--------+
 | 性別   | 数学   |
-+--------+--------+
 | 男     | 85     |
 | 女     | 43     |
 | 女     | 72     |
 | 男     | 94     |
-+--------+--------+

SELECT項目とGROUP BYの項目が一致していますね。

これでエラーは解消され、男女別の数学の点数を重複除外で表示します。

一番シンプルな解決策です。

解消法(その2):DISTINCTを指定する

GROUP BY句を使用せずに、SELECTでDISTINCTを指定します。

単に重複データを削除したいだけなら、GROUP BYよりDISTINCTの方が記述量が少なくて済みます。

例)DISTINCTを指定して解消

SELECT
    DISTINCT 性別, 数学
FROM クラス;
-+--------+--------+
 | 性別   | 数学   |
-+--------+--------+
 | 男     | 85     |
 | 女     | 43     |
 | 女     | 72     |
 | 男     | 94     |
-+--------+--------+

GROUP BY句を無くして、DISTINCTで代用していますね。

なお、

GROUP BYとDISTINCTの実行速度は環境・状況により異なります。

解消法(その3):SELECTしたい項目に集約関数を使用する

GROUP BYを指定されていないSELECT項目に集約関数を使用します。

例)集約関数MAX(最大を求める関数)で解消

SELECT
    性別, MAX(数学)
FROM クラス
GROUP BY 性別;
-+--------+--------+
 | 性別   | 数学   |
-+--------+--------+
 | 女     | 72     |
 | 男     | 94     |
-+--------+--------+

Group By句に数学は追加してませんが、SELECT句にMAX(数学)としてますね。

こうすると、性別毎の数学の最高得点が取得できます。

解消法(その4):分析関数を使用する

GROUP BYを指定していな項目に対して、分析関数(※)を使用して解消できます。
※)分析関数はwindow関数とも呼ばれます

「GROUP BY」の代わりに「PARTITION BY 」をSELECT項目の末尾にOVERを付けて指定します。

例)分析関数で解消

SELECT
    性別, 数学, MAX(数学) OVER(PARTITION BY 性別) AS 数学MAX
FROM クラス;
+-----------------+--------+--------+------+
| 名前            | 性別   | 数学   | 数学MAX  |
+-----------------+--------+--------+------+
| 青葉 一郎      | 男     | 85     | 94   |
| 石野 真央      | 女     | 43     | 72   |
| 田中 佐助      | 男     | 85     | 94   |
| 月野 弥生      | 女     | 72     | 72   |
| 林田 啓二      | 男     | 94     | 94   |
| 山田 花子      | 女     | 43     | 72   |
+-----------------+--------+--------+

 

分析関数は難しいので、少し解説します。

OVER(PARTITION BY 性別)
の部分がGROUP BY 性別の代わりとなります。
GROUP BYより分析関数の方が問合せ速度は早いです。

また、
MySQLはバージョン8.0から分析関数(Window関数)が使用できます。
MariaDBはバージョン10.2から分析関数が使用できます。

バージョン10.2未満だと、下記のようなエラーがでちゃう(-_-)

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(PARTITION BY 性別) AS avg
from クラス' at line 5

(上記の例題で扱った分析関数付きSELECT文を実行した場合のエラー)



スポンサーリンク

MariaDB(MySQL)はGROUP BY未指定でもエラーじゃない

MariaDB(MySQL)の場合、

GROUP BY句において、
SELECT項目に集約していない(GROUP BYを指定してない)項目
を使用してもエラーになりません。

え!結果は何を返すの?
たろちゃん
たろちゃん


SEおっさん
SEおっさん
アテにならない不確定な値を返すぞい

例えば、こんなSQLを実行したとします。

SELECT
    性別, 数学
FROM クラス
GROUP BY 性別;

Oracleの場合、『ORA-00979: GROUP BYの式ではありません。』のエラーとなりますが、

MariaDB(MySQL)の場合、エラーとならずに不確定な値(項目:数学)を返してます。

+--------+--------+
| 性別   | 数学   |
+--------+--------+
| 女     | 74     |
| 男     | 36     |
+--------+--------+

どの行を引っ張ってきてるかワカラナイ仕様です。

正直、エラーを返した方がマシやと思うねんけど…

 

SEおっさん
SEおっさん
ここまで読んでくれてありがとう!

「記事を読んでもわからないトコがある」
「おっさんに何かお願いできないかな?」
という時は、おっさんココナラまで♪



スポンサーリンク
  • このエントリーをはてなブックマークに追加
  • LINEで送る

コメントを残す

*