他のバージョンの文書 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

F.18. intagg — 整数型の集約子と列挙子 #

intaggモジュールは整数型の集約子と列挙子を提供します。 その能力の上位集合を提供する組み込み関数が存在しますので、intaggは現在使われません。 しかし、このモジュールは組み込み関数の互換ラッパーとして今でもまだ提供されています。

F.18.1. 関数 #

集約子は、正確に提供する整数のみを含む整数型配列を生成するint_array_aggregate(integer)集約関数です。 これは任意の配列型で同じことを行うarray_aggのラッパーです。

列挙子は、setof integerを返すint_array_enum(integer[])関数です。 これは基本的に上記集約子の反対の操作を行います。 指定された整数型配列を行集合に拡張します。 これは任意の配列型で同じことを行うunnestのラッパーです。

F.18.2. 使用例 #

多くのデータベースシステムは多対多のテーブルを持ちます。 こうしたテーブルは通常、以下のように2つのインデックス用のテーブルの間に存在します。

CREATE TABLE left_table  (id INT PRIMARY KEY, ...);
CREATE TABLE right_table (id INT PRIMARY KEY, ...);
CREATE TABLE many_to_many(id_left  INT REFERENCES left_table,
                          id_right INT REFERENCES right_table);

通常以下のように使用されます。

SELECT right_table.*
FROM right_table JOIN many_to_many ON (right_table.id = many_to_many.id_right)
WHERE many_to_many.id_left = item;

これは、左辺のテーブル内にある項目に対応した、右辺のテーブル内のすべての項目を返します。 これはSQLで非常によく使用される式です。

さて、この方法論はmany_to_manyテーブル内に非常に多数の項目がある場合に扱いにくくなることがあり得ます。 しばしばこうした結合は、インデックススキャンと特定された左辺の項目に対応した右辺のテーブル内の項目をそれぞれ取り出すことになります。 非常に動的なシステムでは、できることは多くありません。 しかし、ほぼ静的なデータが一部にある場合、集約子を使用して要約テーブルを作成することができます。

CREATE TABLE summary AS
  SELECT id_left, int_array_aggregate(id_right) AS rights
  FROM many_to_many
  GROUP BY id_left;

これは左辺項目毎に1行を持ち、右辺の項目の配列をもつテーブルを作成します。 さて、これは配列を使用する何らかの方法がないとかなり使い勝手が悪くなります。 これが配列列挙子が存在する理由です。 以下を行うことができます。

SELECT id_left, int_array_enum(rights) FROM summary WHERE id_left = item;

上のint_array_enumを使用した問い合わせは、以下と同じ結果を生成します。

SELECT id_left, id_right FROM many_to_many WHERE id_left = item;

違いは、要約テーブルに対する問い合わせはテーブルから1行だけを取り出す必要があるのに対し、直接many_to_manyに問い合わせる場合はインデックススキャンと各項目に対し行を取り出さなければならないという点です。

あるシステムではEXPLAINを行うと8488というコストを持つ問い合わせが329というコストまで減少しました。 元の問い合わせはmany_to_manyテーブルを含む結合でしたが、以下のように置き換えられました。

SELECT id_right, count(id_right) FROM
  ( SELECT id_left, int_array_enum(rights) AS id_right
    FROM summary
    JOIN (SELECT id FROM left_table
          WHERE id = item) AS lefts
    ON (summary.id_left = lefts.id)
  ) AS list
  GROUP BY id_right
  ORDER BY count DESC;