被遗忘的赋值运算符“=”和普通的“:=”
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-like“x = x + y”。 尽管C还没有被发明,这种批评仍然发生。
1972年 – 丹尼斯·里奇发明了一个强大的枪,同时向前和向后射击。 他对C和Unix发明的这一发明造成的死亡和永久性伤害数量不满意。
在PL / PgSQL解析器中,赋值运算符被定义为
assign_operator : '=' | COLON_EQUALS ;
至少自1998年以来,这是一个遗留的功能,出现在PostgreSQL源代码中。
从版本9.4开始,它被记录在案 。
在pgsql用户列表中引发了这种特殊情况 – 在同一个事物上有两个运算符 – 有人要求将其删除,但仍然保留在核心中,因为传统代码的公平语料库依赖于它。
查看Tom Lane(核心Pg开发人员)的消息 :
首先介绍一下(根据官方的Git回购): http : //git.postgresql.org/gitweb/? p=postgresql.git;a=commit;h= 863a62064cfc2b706dd6ab45487d15cc33cedb35
所以,直接回答你的问题:
我没有找到提及和/或解释这个的文档中的一些部分吗?
你没有找到它,因为它是无证的,从版本9.4开始是固定的。
是否有任何已知的后果使用=而不是:=。
使用=没有任何副作用,但是您应该使用:=作为赋值,以使您的代码更具可读性,(作为副作用)更符合PL / SQL。
更新:在罕见的情况下可能会有一个副作用(参见Erwin的答案)
更新:答复更新感谢来自丹尼尔,桑迪等人的意见。
Q1
这个最终被添加到Postgres 9.4的官方文档中 :
为PL / pgSQL变量赋值为:
variable { := | = } expression;
[…]等于(
=
)可以用来代替PL / SQL兼容:=
。
Q2
是否有任何已知的后果使用
=
而不是:=
?
是的 ,我遇到了一个严重的后果 :函数调用命名参数 – 这是相关的,但不完全一样的东西。
严格来说,在这种情况下的区别是在SQL代码中进行的。 但这是一个毫无戒心的程序员的学术差异。 1
考虑一下功能:
CREATE FUNCTION f_oracle(is_true boolean = TRUE) -- correct use of "=" RETURNS text AS $func$ SELECT CASE $1 WHEN TRUE THEN 'That''s true.' WHEN FALSE THEN 'That''s false.' ELSE 'How should I know?' END $func$ LANGUAGE sql;
另外:注意在函数定义中(正确)使用=
。 这是一个SQL任务。 2
带有命名符号的函数调用:
SELECT * FROM f_oracle(is_true := TRUE);
Postgres标识:=
作为参数分配,一切正常。 然而:
SELECT * FROM f_oracle(is_true = TRUE);
由于=
是SQL相等运算符,因此Postgres在调用语句的上下文is_true = TRUE
解释为SQL表达式,并在将结果作为未命名的位置参数传递之前尝试对其进行求值。 它在外部范围中查找一个标识符is_true
。 如果找不到:
ERROR: column "is_true" does not exist
幸运的是,幸运的是,这也是常见的情况。
当在外部范围中可以找到is_true = TRUE
, is_true = TRUE
是一个boolean
结果的有效表达式,被该函数接受。 没有错误发生。 显然,这是程序员使用SQL相等运算符的意图=
…
这个SQL小提琴演示效果。
如果您不了解=
和:=
之间的区别,则很难调试。
始终使用正确的操作员。
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:use =>
now
从这个版本开始,使用SQL标准运算符=>
。 :=
仍支持向后兼容。 但是在新代码中使用标准运算符时,不需要在旧版本上运行。
- 在手册中记载使用命名符号一章。
- 这里是GIT中的解释提交。
重要说明: 这只适用于函数调用中的命名参数赋值(SQL作用域),而不适用于赋值运算符:=
在plpgsql代码中保持不变。
对我自己的问题的部分回答:
PL / pgSQL部分获取结果状态显示了两个使用特殊语法的示例:
GET DIAGNOSTICS variable = item [ , ... ]; GET DIAGNOSTICS integer_var = ROW_COUNT;
我尝试了两个:=
和=
他们都工作。
但GET DIAGNOSTICS
是特殊的语法,所以可以争论,这也不是一个正常的PL / pgSQL分配操作。
阅读Postgresql 9文档:
此页面在运算符优先级的表格中列出了“=”作为赋值运算符。
但奇怪的是这个页面 (赋值运算符文档)没有提到它。