

PostgreSQLのARRAY_AGGでユニークな配列を取得する
この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。
ARRAY_AGGにDISTINCTを付けると、集約結果を重複なしの配列として取得できる。よく使う書き方なのでメモしておく。
使い方
SELECT parent.id, parent.created_at, ARRAY_AGG(DISTINCT child.value) AS valuesFROM parentJOIN child ON parent.id = child.parent_idGROUP BY parent.id, parent.created_at;parentとchildをJOINすると、親レコード1件に対して子レコードが複数行紐づく。単純にARRAY_AGG(child.value)とすると、子レコード側の値が重複していればそのまま配列に入ってしまう。DISTINCTを挟むことで、集約前に重複を除いてから配列化できる。
順序を揃えたい場合はORDER BYが必要
ARRAY_AGG(DISTINCT ...)は要素の順序を保証しない。配列内の並び順も揃えたい場合はORDER BYを一緒に書く。
ARRAY_AGG(DISTINCT child.value ORDER BY child.value)これを書かないと、実行するたびに配列内の並びが変わる可能性がある。
GROUP BYについて
GROUP BYには「SELECTに出す非集約カラムは全部書く」のがPostgreSQLのルール。今回parent.idとparent.created_atは両方SELECTに出しているので、両方ともGROUP BYに必要になる。
ただしPostgreSQLには例外があって、parent.idが主キーならparent.created_atは省略できる。
-- parent.idが主キーならこれでも動くGROUP BY parent.id主キーに関数従属するカラム(同じテーブルの他のカラム)は、主キーさえGROUP BYに入っていれば自動的に一意に定まるとPostgreSQLが判断してくれるため。
ただしこの省略ルールはPostgreSQL固有の挙動で、MySQLの古いバージョンなど他のDBでは同じ書き方がエラーになることがある。動くかどうかを主キー判定に頼らず、SELECTに出すカラムは律儀に全部GROUP BYに書いておいた方が、DB移植や他の人が読むときに事故りにくい。