49

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

所以,问题是:

  • 我没有在文档中找到一些提到和/或解释这一点的部分吗?
  • =使用而不是有任何已知后果:=吗?

编辑/脚注:

请像A Brief, Incomplete, and Mostly Wrong History of Programming Languages中那样眨眼“更现代”的部分:

1970 - Niklaus Wirth 创建了 Pascal,一种程序语言。批评者立即谴责 Pascal,因为它使用“x := x + y”语法而不是更熟悉的 C 语言“x = x + y”。尽管 C 还没有被发明出来,但这种批评还是发生了。

1972 - Dennis Ritchie 发明了一种强大的枪,可以同时向前和向后射击。对他发明 C 和 Unix 的发明造成的死亡和永久残废的数量不满意。

4

4 回答 4

54

在 PL/PgSQL 解析器中,赋值运算符定义为

assign_operator : '='
                | COLON_EQUALS
                ;

这是一个遗留功能,自 1998 年引入源代码以来就存在于源代码中 - 正如我们在PostgreSQL Git repo中看到的那样。

从 9.4 版开始,它被正式记录在案

这种特性——同一事物有两个运算符——在 pgsql 用户列表中提出,有些人要求将其删除,但它仍然保留在核心中,因为遗留代码的公平语料库依赖于它。

请参阅来自 Tom Lane(核心 Pg 开发人员)的此消息。

所以,直接回答你的问题:

我没有在文档中找到一些提到和/或解释这一点的部分吗?

您没有找到它,因为它没有记录,从 9.4 版开始已修复。

使用 = 而不是 := 是否有任何已知后果。

使用=没有副作用,但您应该使用:=进行赋值以使您的代码更具可读性,并且(作为副作用)与 PL/SQL 更兼容。

更新:在极少数情况下可能会有副作用(见欧文的回答)


更新:感谢 Daniel、Sandy 和其他人的意见更新了答案。

于 2011-10-03T22:10:23.463 回答
39

第一季度

这最终被添加到 Postgres 9.4的官方文档中:

一个 PL/pgSQL 变量的赋值写成:

variable { := | = } expression;

=[...]可以使用Equal ( ) 代替 PL/SQL-compliant :=

第二季度

=使用而不是有任何已知后果:=吗?

的,我遇到了一个后果严重的案例:使用命名参数的函数调用- 这是相关但不完全相同的事情。

严格来说,这种情况下的区别是在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;

另外:注意=函数定义中的正确使用。这是CREATE FUNCTION语法的一部分——以SQL赋值的方式。2

使用命名符号的函数调用:

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

这是幸运的情况,幸运的是,也是常见的情况。

Whenis_true 可以在外部范围内找到(并且数据类型兼容),is_true = TRUE是一个有效的表达式,其boolean结果被函数接受。不会发生错误。显然,这是程序员使用SQL相等运算符的意图=......

这个SQL Fiddle演示了效果。

如果您不知道 和 之间的区别,则很难=调试:=
始终使用正确的运算符。


1在函数调用中使用,只有:=正确的赋值运算符。这适用于所有语言的函数,不仅仅是 PL/pgSQL,直到并包括 pg 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 标准运算符=>:=仍然支持向后兼容。但是在不需要在非常旧的版本上运行的新代码中使用标准运算符。

这适用于函数调用(SQL 范围)中的命名参数赋值,而不适用:=于保持不变的 plpgsql 代码中的赋值运算符。

于 2014-02-24T23:14:38.633 回答
3

我自己的问题的部分答案:

PL/pgSQL 部分获取结果状态显示了两个使用特殊语法的示例:

GET DIAGNOSTICS variable = item [ , ... ]; 
GET DIAGNOSTICS integer_var = ROW_COUNT;

我都试过了:==而且它们都有效。

但这GET DIAGNOSTICS是一种特殊的语法,因此有人可以争辩说,这也不是一个正常的 PL/pgSQL 赋值操作。

于 2011-09-22T19:33:11.003 回答
1

阅读 Postgresql 9 文档:

此页面将“=”列为运算符优先级表中的赋值运算符。

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

于 2011-09-22T19:00:11.100 回答