假设我有一个名为t的表,它存储在postgresql数据库中。 我有6列名为a,b,c,d,e,f。 列a,b和c取0到100之间的值,但是在aritmetic scale 0 <0。 a&lt; b&lt; c&lt; 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
有人可以告诉我,我错了所以我可以继续计算所需的平均值吗?
答案 0 :(得分:3)
我完全赞同Erwin的答案中的所有内容,但是想指出另一个选项。您可以创建一种“生成的列”,将按需计算,如下所示:
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规划器会查找该名称的函数,该函数将表的记录类型作为其唯一参数,并执行该函数。有时这种方法比使用视图更方便,尽管效果基本相同。
答案 1 :(得分:2)
错误的直接原因是命名冲突。您可以定义参数t
和g
,并在ALTER TABLE
语句中使用相同的名称。我养成了为参数名称添加前缀的习惯(例如_t
,_g
),这样它们就不会与函数体中的其他名称冲突。
此外,您的参数不应定义为character varying
,因为它们包含数值。使用适当的numerical type,可能是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;