被遗忘的赋值运算符“=”和普通的“:=”

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 = TRUEis_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文档:

此页面在运算符优先级的表格中列出了“=”作为赋值运算符。

但奇怪的是这个页面 (赋值运算符文档)没有提到它。