带有 IF ELSE 语句的 postgresql plpsql 函数
Posted
技术标签:
【中文标题】带有 IF ELSE 语句的 postgresql plpsql 函数【英文标题】:postgresql plpsql function with IF ELSE statement 【发布时间】:2012-05-06 20:26:48 【问题描述】:假设我有一个名为 t 的表,它存储在 postgresql 数据库中。 我有 6 列名为 a、b、c、d、e、f。 a、b 和 c 列取 0 到 100 之间的值,但在算术尺度上 0
我想计算 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
有人能告诉我我错了吗,这样我就可以继续计算所需的平均值了吗?
【问题讨论】:
您不能以这种方式将表名作为参数传递。但是每次运行该函数时添加一个新列似乎没什么用。你为什么要这么做? 感谢您的积分!关于 SET 命令, indedd 是错误的。但是我可以在 SET 中使用 IF 吗?我将如何使用它? 'UPDATE t SET g = D IF a > 50'? 【参考方案1】:错误的直接原因是命名冲突。您定义参数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;
【讨论】:
感谢您的积分!但是函数中没有使用参数?在我定义它们之后,我应该添加要在函数中使用的变量吗? 关于你对CASE函数的想法,我在创建函数之前已经申请过了。它确实计算了一些东西,但是当我进行验证时,似乎在 CASE 函数中您不能使用不同的列,因为如果第一个 WHEN 条件为真,则评估停止。因此,当第一个条件为真时,值设置为 d,但不评估第二个条件,但这是我需要的,在条件为假时进行平均。 @MihaiNiculita 然后你应该调整你的条件是互斥的。如果您希望在b > 50
时跳过第一个THEN
子句,则将其用作您的第一个WHEN
:a > 50 AND b <= 50
(相当于a > 50 AND NOT b > 50
)。【参考方案2】:
我完全同意 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 PostgreSQL 的一个很酷的特性!一个相关的问题出现了,我添加了一个详细的解释说明为什么会这样:***.com/questions/11165450/…以上是关于带有 IF ELSE 语句的 postgresql plpsql 函数的主要内容,如果未能解决你的问题,请参考以下文章
带有if和else语句的foreach循环在if语句为假时不执行else语句