提问人:A.H. 提问时间:9/18/2011 最后编辑:moodymudskipperA.H. 更新时间:5/21/2022 访问量:14129
被遗忘的赋值运算符“=”和司空见惯的“:=”
The forgotten assignment operator "=" and the commonplace ":="
问:
PL/pgSQL 的文档说,变量的声明和赋值是用 .
但是一个简单、更短、更现代(见脚注)似乎按预期工作::=
=
CREATE OR REPLACE FUNCTION foo() RETURNS int AS $$
DECLARE
i int;
BEGIN
i = 0;
WHILE NOT i = 25 LOOP
i = i + 1;
i = i * i;
END LOOP;
RETURN i;
END;
$$ LANGUAGE plpgsql;
> SELECT foo();
25
请注意,Pl/pgSQL 可以清楚地区分赋值和比较,如行所示
WHILE NOT i = 25 LOOP
所以,问题是:
- 我没有在文档中找到一些提到和/或解释这一点的部分吗?
- 是否有任何已知的后果使用代替?
=
:=
编辑/脚注:
请眨眨眼,“更现代”的部分,就像在《编程语言的简短、不完整和大多错误的历史》中一样:
1970 年 - Niklaus Wirth 创建了 Pascal,一种程序语言。评论家 立即谴责 Pascal,因为它使用了 “x := x + y” 语法 而不是更熟悉的类似 C 的“x = x + y”。这种批评 尽管 C 尚未被发明,但还是发生了。
1972年 - 丹尼斯·里奇(Dennis Ritchie)发明了一种强大的枪,可以向前射击 和向后同时。对死亡人数不满意 以及他发明的 C 和 Unix 的发明造成的永久残缺。
答:
阅读 Postgresql 9 文档:
此页面在有关运算符优先级的表中列出“=”作为赋值运算符。
但奇怪的是,这个页面(分配运算符文档)没有提到它。
评论
=
:=
UPDATE table SET column **=** value
对我自己的问题的部分回答:
PL/pgSQL 部分获取结果状态显示了两个使用特殊语法的示例:
GET DIAGNOSTICS variable = item [ , ... ];
GET DIAGNOSTICS integer_var = ROW_COUNT;
我两者都试过了,它们都有效。:=
=
但是是特殊的语法,所以可以说,这也不是正常的PL / pgSQL赋值操作。GET DIAGNOSTICS
评论
在 PL/PgSQL 解析器中,赋值运算符定义为
assign_operator : '='
| COLON_EQUALS
;
这是一个遗留功能,自 1998 年引入以来就存在于源代码中 - 正如我们在 PostgreSQL Git 存储库中看到的那样。
从版本 9.4 开始,它被正式记录在案。
这种特质 - 有两个运算符用于同一事物 - 在pgsql用户列表中被提出,有些人要求将其删除,但它仍然保留在核心中,因为遗留代码的公平语料库依赖于它。
请参阅来自 Tom Lane(核心 Pg 开发人员)的此消息。
因此,要直接回答您的问题:
我没有在文档中找到一些提到和/或解释的部分吗? 这?
您没有找到它,因为它没有文档,从版本 9.4 开始已修复。
使用 = 而不是 := 是否有任何已知的后果。
使用 = 没有附带后果,但您应该使用 := 进行赋值,以使代码更具可读性,并且(作为副作用)与 PL/SQL 更兼容。
更新:在极少数情况下可能会有副作用(参见 Erwin 的回答)
更新:由于丹尼尔、桑迪和其他人的输入,答案已更新。
评论
=
问题1
对 PL/pgSQL 变量的值赋值写成:
variable { := | = } expression;
[...]可以使用 equal () 代替 PL/SQL 兼容。
=
:=
问题2
是否有任何已知的后果使用代替?
=
:=
是的,我有一个后果严重的案例:使用命名参数的函数调用 - 这是相关的,但不完全相同。
严格来说,在这种情况下,区别是在 SQL 代码中进行的。但对于毫无戒心的程序员来说,这是一种学术上的差异。1
考虑以下函数:
CREATE FUNCTION f_oracle(is_true boolean = TRUE) -- correct use of "="
RETURNS text
LANGUAGE sql AS
$func$
SELECT CASE $1
WHEN TRUE THEN 'That''s true.'
WHEN FALSE THEN 'That''s false.'
ELSE 'How should I know?'
END
$func$;
请注意函数定义中的正确用法。这是语法的一部分 - 采用 SQL 赋值的样式。阿拉伯数字=
CREATE FUNCTION
使用命名表示法的函数调用:
SELECT * FROM f_oracle(is_true := TRUE);
Postgres 标识为参数分配,一切都很好。但是::=
SELECT * FROM f_oracle(is_true = TRUE);
由于 =
是 SQL 相等运算符,因此 Postgres 在调用语句的上下文中解释为 SQL 表达式,并尝试在将结果作为未命名的位置参数传递之前对其进行评估。它在外部作用域中查找标识符。如果找不到:is_true = TRUE
is_true
ERROR: column "is_true" does not exist
这是幸运的情况,幸运的是,也是常见的情况。
When can be found in the outer scope(并且数据类型兼容)是一个有效的表达式,其结果被函数接受。不会发生错误。显然,这是程序员使用 SQL 相等运算符的意图......is_true
is_true = TRUE
boolean
=
此 db<>fiddle 演示了该效果。
旧 sqlfiddle
如果您不知道 和 之间的区别,则很难调试。
始终使用正确的运算符。=
:=
1 在函数调用中使用命名表示法时,只有 :=
是正确的赋值运算符。这适用于所有语言的函数,而不仅仅是 PL/pgSQL,直到第 9.4 页。见下文。
2 可以使用 =
(或 )来定义函数参数的默认值。这与手头的问题没有任何关系。它只是非常接近不正确的用例。DEFAULT
Postgres 9.0 - 9.4:从:=
=>
分配给命名函数参数的 SQL 标准是 =>
(Oracle 的 PL/SQL 使用它。Postgres 无法执行相同的操作,因为运算符以前是未保留的,因此它改用 PL/pgSQL 的赋值运算符。随着 Postgres 9.0 的发布,已弃用用于其他目的。发行说明::=
=>
不推荐使用 => 作为运算符名称 (Robert Haas)
PostgreSQL 的未来版本可能会拒绝此运算符名称 完全,以便支持 SQL 标准表示法 函数参数。目前,它仍然是允许的,但 定义此类运算符时,将发出警告。
如果您应该用于其他用途,请停止并停止。它将来会坏掉。=>
Postgres 9.5:立即使用=>
从此版本开始,将使用 SQL 标准运算符 =>
。 仍支持向后兼容。但是在不需要在非常旧的版本上运行的新代码中使用标准运算符。:=
- 记录在手册的“使用命名表示法”一章中。
- 这是 GIT 中的带有解释的提交。
这适用于函数调用(SQL 作用域)中的命名参数赋值,不适用于 plpgsql 代码中的赋值运算符,后者保持不变。:=
评论
=
:=
=
:=