41

PostgreSQL を使用すると、次のようなクエリがいくつかあります。

SELECT <col 1>, <col 2>
     , (SELECT sum(<col x>)
        FROM   <otherTable> 
        WHERE  <other table foreignkeyCol>=<this table keycol>) AS <col 3>
FROM   <tbl>

副選択がすべての場合で同一であることを考えると、その副選択を疑似列としてテーブルに格納する方法はありますか? 基本的に、レコードが関連付けられているテーブル B の特定の列の合計であるテーブル A から列を選択できるようにしたいと考えています。これは可能ですか?

4

4 に答える 4

87

そのサブセレクトを疑似列としてテーブルに格納する方法はありますか?

VIEWアドバイスされているようなものは、完全に有効な解決策です。頑張れ。

しかし、あなたの質問にさらに密接に適合する別の方法があります。「計算フィールド」または「生成された列」をエミュレートするために、テーブル型をパラメーターとして受け取る関数を作成できます。

あなたの説明から派生したこのテストケースを考えてみましょう:

CREATE TABLE tbl_a (a_id int, col1 int, col2 int);
INSERT INTO tbl_a VALUES (1,1,1), (2,2,2), (3,3,3), (4,4,4);

CREATE TABLE tbl_b (b_id int, a_id int, colx int);
INSERT INTO tbl_b VALUES
  (1,1,5),  (2,1,5),  (3,1,1)
, (4,2,8),  (5,2,8),  (6,2,6)
, (7,3,11), (8,3,11), (9,3,11);

エミュレートする関数を作成しますcol3:

CREATE FUNCTION col3(tbl_a)
  RETURNS int8
  LANGUAGE sql STABLE AS
$func$
SELECT sum(colx)
FROM   tbl_b b
WHERE  b.a_id = $1.a_id
$func$;

これで、次のクエリを実行できます。

SELECT a_id, col1, col2, tbl_a.col3
FROM   tbl_a;

あるいは:

SELECT *, a.col3 FROM tbl_a a;

だけでなくtbl_a.col3/の書き方に注意してください。これは不可欠です。a.col3col3

Oracleの「仮想列」とは異なりSELECT * FROM tbl_a . そのためにa を使用できますVIEW

なぜこれが機能するのですか?

テーブルの列を参照する一般的な方法は、属性表記を使用することです。

tbl_aから tbl_a.col1を選択します。

関数を呼び出す一般的な方法は、関数表記法です。

SELECT col3(tbl_a) ;

一般に、SQL 標準に準拠するこれらの正規の方法に固執するのが最善です。

ただし、Postgres では属性表記も使用できます。これらも同様に機能します:

SELECT col1(tbl_a) FROM tbl_a;
SELECT tbl_a.col3 ;

詳しくはマニュアルで。
おそらく、これがどこに向かっているのか、もうおわかりでしょう。これは、テーブルの余分な列を追加するように見えますが、実際には現在の行(またはそのエイリアス) を行タイプの引数として取り、値を計算する関数です。tbl_acol3()tbl_a

SELECT *, a.col3
FROM   tbl_a AS a;

実際の列がある場合、それが優先され、システムは行をパラメータとしてcol3取るその名前の関数を探しません。tbl_a

その「美しさ」: から列を追加または削除できtbl_a、最後のクエリは現在のすべての列を動的に返します。ビューは、作成時に存在した列のみを返します (アーリー バインディングと のレイト バインディング*)。
もちろん、ここでテーブルを削除する前に、依存する関数を削除する必要があります。また、テーブルに変更を加えるときに関数を無効にしないように注意する必要があります。

私はまだそれを使用しません。無実の読者にとってはあまりにも驚くべきことです。

于 2012-06-23T02:19:22.223 に答える
3

ビューとは別に、合計の関数を作成できます。

CREATE FUNCTION sum_other_table( key type_of_key ) RETURNS bigint
AS $$ SELECT sum( col_x ) FROM table_1 where table_1.key = key $$ LANGUAGE SQL;

それをアグリゲーターとして使用します。

SELECT col_1, col_2, sum_other_table( key ) AS col_3
FROM table_2 WHERE table_2.key = key;

sum_other_table() の戻り値の型は、合計する列の型に依存することに注意してください。

于 2012-06-23T00:15:42.240 に答える
3

これまでのところ3つの答えがあり、すべてうまくいきます。状況によっては、それらのいずれかが「最善の解決策」になる可能性があります。小さなテーブルでは、パフォーマンスはかなり近いはずですが、何百万行もあるテーブルにうまくスケーリングできるものはありません。大規模なデータセットで目的の結果を得る最速の方法は、おそらく次のようになります (Erwin のセットアップを使用):

SELECT a_id, col1, col2, sum(colx)
FROM tbl_a LEFT JOIN tbl_b b using(a_id)
GROUP BY a_id, col1, col2;

a_idが主キーとして宣言されていて、これが 9.1 以降で実行されている場合、 と が機能的に に依存しているため、句を簡略できGROUP BYます。col1col2a_id

SELECT a_id, col1, col2, sum(colx)
FROM tbl_a LEFT JOIN tbl_b b using(a_id)
GROUP BY a_id;

ビューはこのように定義でき、スケーリングしますが、関数を使用するアプローチですべて同じ実行パスが考慮されるとは思わないため、最速の実行パスが使用されない可能性があります

于 2012-06-23T16:36:59.613 に答える
3

ライオンのコメントによると、どうやらこれはビューで処理されるようです。したがって、私の場合、次のコマンドを使用しました。

CREATE VIEW <viewname> AS
SELECT *, (SELECT sum(<col x>)
FROM   <otherTable
WHERE  <otherTable foreignkeyCol>=<thisTable keycol>) AS <col 3>
FROM   <tablename>

これにより、基本的に、目的の列を含む別のテーブルが得られます。

于 2012-06-23T00:13:02.617 に答える