職業プログラマの休日出勤

職業プログラマによる日曜自宅プログラミングや思考実験の成果たち。リアル休日出勤が発生すると更新が滞りがちになる。記事の内容は個人の意見であり、所属している(いた)組織の意見ではない。

PostgreSQLのGroup By

1年半くらい前に、こんな記事を書きました。
MySQLのGroup By - 職業プログラマの休日出勤
MySQLのこのような仕様のせい(?)で、バグの発見が遅くなってしまった、という話です。

先日、SQLWorld★大阪 #21 というイベントに参加してきましたが、そこで得た情報の一つに、PostgreSQLのGroupByにも上記のMySQLのやつと似たようなのがある、というものがありました。
この記事は、その「不思議な」Group Byの動作を検証するものです。

テストデータ

CREATE TABLE test20140127
(
  pkey1 integer NOT NULL,
  pkey2 character varying(10) NOT NULL,
  data1 text,
  CONSTRAINT pkey_of_test20140126 PRIMARY KEY (pkey1, pkey2)
)
WITH (
  OIDS=TRUE
);
INSERT INTO test20140127 VALUES(1, 'foo', 'bar');
INSERT INTO test20140127 VALUES(2, 'foo', 'barr');
INSERT INTO test20140127 VALUES(2, 'foo2', 'barrr');
INSERT INTO test20140127 VALUES(3, 'x', 'brrrrrrrr');

明らかにダメなクエリ

select *
from test20140127
group by data1

こんなクエリがエラーになることは、皆さんも容易に想像できるかと思います。

ERROR:  列"test20140127.pkey1"はGROUP BY句で出現しなければならないか、集約関数内で使用しなければなりません
LINE 1: select *
               ^

ほら。

ぁゃιぃクエリ

さて、ここからが本題です。

次のクエリはどうなるでしょうか?

select *
from test20140127
group by pkey1, pkey2

このクエリ、なんと正常に実行できるのです。
確かに、単一テーブルへの select 文で、 primary key で group by したら、それは問題無さそうです。
その通りなのですが、今まで考えたこともありませんでした。

この機能(?)はPostgreSQLの9.1で入ったそうなのですが、何故こんなぁゃιぃ機能をわざと入れたのか疑問に思っていました。
気になって9.1のReleaseNoteを見てみると、

Allow non-GROUP BY columns in the query target list when the primary key is specified in the GROUP BY clause (Peter Eisentraut)
The SQL standard allows this behavior, and because of the primary key, the result is unambiguous.

http://www.postgresql.org/docs/9.1/interactive/release-9-1.html

ということでした。SQL標準に規定されているんです。知りませんでした。

この機能を積極的に使うといったことは、実務ではまずあり得ないでしょうけれども、頭の片隅には置いておきたいものです。

検証環境

PostgreSQL 9.3.2


PostgreSQL全機能バイブル

PostgreSQL全機能バイブル