我创建了
person
表,然后在其中插入了 2 行,如下所示:
CREATE TABLE person (
id INT,
name VARCHAR(20),
age INT
);
INSERT INTO person (id, name, age)
VALUES (1, 'John', 27), (2, 'David', 32);
然后使用 EXECUTE 语句,我使用
my_func()
和 my_age
参数创建了 my_id
,如下所示:
CREATE FUNCTION my_func(my_age INT, my_id INT) RETURNS VOID AS $$
BEGIN -- ↑↑↑↑↑↑ ↑↑↑↑↑
EXECUTE 'UPDATE person SET age = $1 WHERE id = $2' USING my_age, my_id;
END;
$$ LANGUAGE plpgsql;
或者:
CREATE FUNCTION my_func(my_age INT, my_id INT) RETURNS VOID AS $$
BEGIN
EXECUTE 'UPDATE person SET age = $1 WHERE id = $2' USING $1, $2;
END;
$$ LANGUAGE plpgsql;
然后,调用
my_func()
可以将age
的David
更新为56
,如下所示:
postgres=# SELECT my_func(56, 2);
my_func
---------
(1 row)
postgres=# SELECT * FROM person;
id | name | age
----+-------+-----
1 | John | 27
2 | David | 56
(2 rows)
接下来,在没有
EXECUTE
语句的情况下,我使用 my_func()
和 my_age
参数创建了 my_id
,如下所示:
CREATE FUNCTION my_func(my_age INT, my_id INT) RETURNS VOID AS $$
BEGIN -- ↑↑↑↑↑↑ ↑↑↑↑↑
UPDATE person SET age = my_age WHERE id = my_id;
END;
$$ LANGUAGE plpgsql;
或者:
CREATE FUNCTION my_func(my_age INT, my_id INT) RETURNS VOID AS $$
BEGIN
UPDATE person SET age = $1 WHERE id = $2;
END;
$$ LANGUAGE plpgsql;
然后,调用
my_func()
可以将age
的David
更新为56
,如下所示:
postgres=# SELECT my_func(56, 2);
my_func
---------
(1 row)
postgres=# SELECT * FROM person;
id | name | age
----+-------+-----
1 | John | 27
2 | David | 56
(2 rows)
那么,有和没有
EXECUTE
语句的函数有什么区别?
使用 EXECUTE 语句,您可以使用
my_func()
和 age
参数创建 id
,它们与 age
和 id
列同名,如下所示:
CREATE FUNCTION my_func(age INT, id INT) RETURNS VOID AS $$
BEGIN -- ↑↑↑ ↑↑
EXECUTE 'UPDATE person SET age = $1 WHERE id = $2' USING age, id;
END; -- ↑↑↑ ↑↑
$$ LANGUAGE plpgsql;
或者:
CREATE FUNCTION my_func(age INT, id INT) RETURNS VOID AS $$
BEGIN -- ↑↑↑ ↑↑
EXECUTE 'UPDATE person SET age = $1 WHERE id = $2' USING $1, $2;
END; -- ↑↑↑ ↑↑
$$ LANGUAGE plpgsql;
然后,调用
my_func()
可以将age
的David
更新为56
,如下所示:
postgres=# SELECT my_func(56, 2);
my_func
---------
(1 row)
postgres=# SELECT * FROM person;
id | name | age
----+-------+-----
1 | John | 27
2 | David | 56
(2 rows)
如果没有
EXECUTE
语句,您仍然可以使用 my_func()
和 age
参数创建 id
,它们与 age
和 id
列同名,如下所示:
CREATE FUNCTION my_func(age INT, id INT) RETURNS VOID AS $$
BEGIN -- ↑↑↑ ↑↑
UPDATE person SET age = age WHERE id = id;
END; -- ↑↑↑ ↑↑
$$ LANGUAGE plpgsql;
或者:
CREATE FUNCTION my_func(age INT, id INT) RETURNS VOID AS $$
BEGIN -- ↑↑↑ ↑↑
UPDATE person SET age = $1 WHERE id = $2;
END; -- ↑↑↑ ↑↑
$$ LANGUAGE plpgsql;
但是,调用上面的
my_func()
会得到下面的错误:
错误:列引用“id”不明确
PL/pgSQL 中的有和没有
语句的函数有什么区别?EXECUTE
EXECUTE
用于动态 SQL。 用于动态构建和执行 SQL 语句。主要涉及来自其他角色的用户或系统目录的输入,而不仅仅是 values - 即 identifiers
或 SQL
code
元素。您通常不会使用
EXECUTE
,除非您需要that。 一个例外:虽然 PL/pgSQL 可以保存和重用 SQL DML 语句的通用查询计划(很像准备好的语句,但只有在执行几次之后,才会有一些复杂性),
EXECUTE
可以防止这种情况发生并强制执行每次执行都有一个新的查询计划。这可以(ab)用于高度不规则的数据分布,其中查询计划针对给定的输入进行了更好的优化(Postgres 本身并没有意识到这一点)。 很难想象这可以适用于您的简单示例。如果
person.id
是PK的话,那肯定不是。基本上,带有
EXECUTE
的版本是(更昂贵、更复杂、更容易出错)废话。相关:
另一个(不重要)副作用:查询字符串在单独的作用域中执行,因此周围代码块的变量和参数在那里不可见。您可以使用
USING
子句传递值。但您当然不需要这种副作用来隐藏命名冲突。只需表限定列名即可。参见:始终小心连接动态 SQL,以防御可能的
SQL 注入!参见:
此外,age
作为表格列通常是无意义的。而是存储生日。