函数调用的属性符号给出错误

Attribute notation for function call gives error

当当前模式与函数之一不同时,属性符号函数调用会出错。

我创建了一个函数

CREATE FUNCTION pub.FullName(pub.reps)
  RETURNS text AS
$func$
       select (.fname || ' ' || .lname)
$func$ LANGUAGE SQL;

我正在尝试使用 docs 中描述的属性符号调用函数:

select r.fullname from pub.reps r;

但是得到一个错误信息:

ERROR:  column "fullname" does not exist

使用函数符号的查询工作正常:

select pub.fullname(r.*) from pub.reps r;

数据库已从 PostgreSQL 10 迁移 backup/restore。

Select version() 给出:PostgreSQL 11.3, compiled by Visual C++ build 1914, 64-bit

UPD。发现如果我将 pub 模式设置为默认模式,那么 select r.fullname from pub.reps r 可以正常工作。

你自己找到了问题的根源。准确地说:函数pub的模式必须在当前search_path中的任何地方列出,不必须是 "default" 或 "current" 架构(列表中的第一个)。相关:

  • How does the search_path influence identifier resolution and the "current schema"

所以 Postgres 没有找到这个函数。在这方面,Postgres 11 与 Postgres 10 没有什么不同。不过,有一些值得注意的相关发展。您提到:

Database has been migrated from PostgreSQL 10 with backup/restore.

考虑 release notes for Postgres 11 中指出的这个细微变化:

  • Consider syntactic form when disambiguating function versus column references (Tom Lane)

    When x is a table name or composite column, PostgreSQL has traditionally considered the syntactic forms f(x) and x.f to be equivalent, allowing tricks such as writing a function and then using it as though it were a computed-on-demand column. However, if both interpretations are feasible, the column interpretation was always chosen, leading to surprising results if the user intended the function interpretation. Now, if there is ambiguity, the interpretation that matches the syntactic form is chosen.

因此,如果 table reps 中还有一列 fullname 并且 您显示的 pub.fullname(pub.reps) 函数,Postgres 10,即使使用函数符号,仍会选择 column:

SELECT fullname(r) FROM reps r;  -- resolves to column if it exists, ignoring function

db<>fiddle here 对于 Postgres 10

Postgres 11(更合理)选择函数:

db<>fiddle here 对于 Postgres 11

Postgres 12(目前是测试版)最终实​​现了真正的生成列。 The release notes:

  • Add support for generated columns (Peter Eisentraut)

The content of generated columns are computed from expressions (including references to other columns in the same table) rather than being specified by INSERT or UPDATE commands.

不过,只有 STORED 生成的列进入了这个版本。 (更有趣的 IMO)VIRTUAL variant was postponed for a later release。 (还没有在 Postgres 13 中。)

您的 table 可能如下所示:

CREATE TABLE pub.reps (
  reps_id  int GENERATED ALWAYS AS IDENTITY PRIMARY KEY 
, fname    text NOT NULL
, lname    text NOT NULL
, fullname text GENERATED ALWAYS AS (fname || ' ' || lname) STORED
);

db<>fiddle here

我声明了 fnamelnameNOT NULL。否则,您的简单连接 (fname || ' ' || lname) 就是一个陷阱。参见:

  • How to concatenate columns in a Postgres SELECT?
  • Combine two columns and add into one new column