3

假设我有一个名为 t 的表,它存储在 postgresql 数据库中。我有 6 列名为 a、b、c、d、e、f。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

我完全同意欧文回答中的所有内容,但想指出另一种选择。您可以创建一种“生成的列”,它将按需计算,如下所示:

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

错误的直接原因是命名冲突。您在语句中定义参数tg使用相同的名称。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 回答