3

postgresql データベースに格納されている t という名前のテーブルがあるとします。a、b、c、d、e、f という名前の 6 つの列があります。列 a、b、および c は 0 から 100 の間の値を取りますが、算術スケールでは 0 < a < b < c < 100 です。列 d、e、および f は、1 から 10 の範囲の任意の値を取ります。

列d、e、およびfの加重平均を計算したいのですが、列a、b、およびcに関連する条件があります。条件は、50 より小さい値を持つ a、b、および c 列でのみ平均が計算されることです。

これには機能が必要だと思うので、それを始めました:

CREATE OR REPLACE FUNCTION example(t character varying, a character varying, b character varying, c character varying, d character varying, e character varying, f character varying, g character varying) RETURNS double precision AS $$

BEGIN
    ALTER TABLE t ADD COLUMN g double precision;
        UPDATE t
            IF a > 50 THEN
                SET g = d;
            ELSE 
                IF b > 50 THEN;
                    SET g = (d+e)/2;
                END IF c > 50 THEN
                        SET g = (d+e+f)/3;
            END IF;
END;
$$ LANGUAGE plpgsql;

次のエラーが表示されます。

ERROR:  syntax error at or near "$1"
LINE 1: ALTER TABLE  $1  ADD COLUMN  $2  double precision
                 ^
QUERY:  ALTER TABLE  $1  ADD COLUMN  $2  double precision
CONTEXT:  SQL statement in PL/PgSQL function "example" near line 2

********** Error **********

ERROR: syntax error at or near "$1"
SQL state: 42601
Context: SQL statement in PL/PgSQL function "example" near line 2

必要な平均の計算を進めることができるように、誰かが私が間違っていたと教えてもらえますか?

4

2 に答える 2

3

Erwinの回答のすべてに完全に同意しますが、もう1つのオプションを指摘したいと思います。次のように、オンデマンドで計算される一種の「生成された列」を作成できます。

CREATE FUNCTION g(rec t)
  RETURNS double precision
  IMMUTABLE
  LANGUAGE SQL
AS $$
  SELECT CASE
           WHEN $1.a > 50 THEN $1.d 
           WHEN $1.b > 50 THEN ($1.d+$1.e)/2
           WHEN $1.c > 50 THEN ($1.d+$1.e+$1.f)/3
           ELSE 0
         END;
$$;

gその後、参照がテーブル名またはエイリアスで修飾されている限り、列と同じように参照できます。例えば:

SELECT *, t.g FROM t;

明らかに修飾された列参照が列に解決されない場合、PostgreSQL プランナーはその名前でテーブルのレコード タイプを唯一のパラメーターとして受け取る関数を探し、その関数を実行します。効果は基本的に同じですが、ビューを使用するよりもこのアプローチの方が便利な場合があります。

于 2012-05-06T23:08:31.223 に答える
3

エラーの直接の原因は名前の競合です。tパラメータを定義し、ステートメントgで同じ名前を使用します。関数本体で他の名前と競合しないように、ALTER TABLEパラメーター名の前に ( 、 など) を付ける習慣をつけています。_t_g

character varyingまた、パラメータは数値を保持するため、定義しないでください。おそらく適切な数値型double precisionを使用してください。

しかし、機能はまったく必要ないと思います。これは、単純な SQL ステートメントで解決できます。

ALTER TABLE tbl ADD COLUMN g double precision;

UPDATE tbl
SET g = CASE
           WHEN a > 50 THEN d 
           WHEN b > 50 THEN (d+e)/2
           WHEN c > 50 THEN (d+e+f)/3
           ELSE 0  -- definition for ELSE case is missing
        END;

g機能的に依存するデータのみを保持するため、アイデア全体を完全にスクラッチして、目的のためにビューを使用することもできます。

CREATE VIEW tbl_with_g AS
SELECT *
     , CASE
          WHEN a > 50 THEN d 
          WHEN b > 50 THEN (d+e)/2
          WHEN c > 50 THEN (d+e+f)/3
          ELSE 0
       END AS g
FROM   tbl;
于 2012-05-06T21:09:13.807 に答える