函数调用的属性表示法给出错误
Posted
技术标签:
【中文标题】函数调用的属性表示法给出错误【英文标题】:Attribute notation for function call gives error 【发布时间】:2019-06-29 09:23:02 【问题描述】:当当前模式与函数之一不同时,属性表示法函数调用会出错。
我已经创建了一个函数
CREATE FUNCTION pub.FullName(pub.reps)
RETURNS text AS
$func$
select ($1.fname || ' ' || $1.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 迁移。
Select version()
给出:PostgreSQL 11.3, compiled by Visual C++ build 1914, 64-bit
UPD。发现如果我将pub
模式设置为默认值,那么select r.fullname from pub.reps r
可以正常工作。
【问题讨论】:
测试数据库在哪个服务器上?为什么混合大小写?你在任何地方都使用过双引号吗? 混合大小写仅是为了便于阅读。它不影响结果。服务器与第一个数据库相同 - 我自己的笔记本电脑。 我发现它取决于当前架构。如果我将 pub 模式设置为默认值,那么select r.FullName from pub.reps r
可以工作。否则我会得到一个错误。
@ErwinBrandstetter,感谢您的详细回答和改进我的帖子。现在看起来好多了。也适用于 dbfiddle 链接。这应该是一个很好的工具。据我了解,如果不修改搜索路径(例如在查询中显式使用模式),就无法使用属性功能。所以我最好等 Postgres 12。
函数的模式必须在搜索路径中,因为无法对属性进行模式限定(变成函数)。严格来说,您没有必须修改search_path
:您始终可以在已经存在的架构中创建函数,pg_catalog
作为最后的措施。 (虽然我宁愿避免将用户对象放在那里。)
【参考方案1】:
你自己找到了问题的根源。准确地说:函数pub
的架构必须在当前search_path
中任何地方列出,不必是“默认”或“当前” " 架构(列表中的第一个)。相关:
所以 Postgres 没有找到这个函数。在这方面,Postgres 11 与 Postgres 10 没有什么不同。不过,有一些值得注意的相关发展。你提到:
数据库已通过备份/恢复从 PostgreSQL 10 迁移。
考虑一下release notes for Postgres 11 中指出的这种细微变化:
在区分函数与列引用时考虑句法形式 (Tom Lane)
当
x
是表名或复合列时,PostgreSQL 有 传统上认为句法形式f(x)
和x.f
是 等效的,允许使用诸如编写函数然后使用之类的技巧 就好像它是一个按需计算的列。但是,如果两者 解释是可行的,列解释总是 如果用户想要 功能解释。现在,如果有歧义, 选择符合句法形式的解释。
所以,如果在表reps
中有一个列fullname
还有你显示的函数pub.fullname(pub.reps)
,Postgres 10,即使使用功能符号,仍然会选择列:
SELECT fullname(r) FROM reps r; -- resolves to column if it exists, ignoring function
dbfiddle here 用于 Postgres 10
Postgres 11(更合理)选择函数:
dbfiddle here 用于 Postgres 11
Postgres 12(目前为测试版)最终实现了真正的生成列。 The release notes:
添加对生成列的支持 (Peter Eisentraut)生成的列的内容是根据表达式计算的 (包括对同一表中其他列的引用)而不是 由
INSERT
或UPDATE
命令指定。
不过,只有 STORED
生成的列进入了这个版本。 (更有趣的 IMO)VIRTUAL
variant was postponed for a later release。 (还没有在 Postgres 13 中。)
您的表格可能如下所示:
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小提琴here
我声明了fname
和lname
列NOT NULL
。否则,您的简单串联 (fname || ' ' || lname
) 是一个陷阱。见:
【讨论】:
以上是关于函数调用的属性表示法给出错误的主要内容,如果未能解决你的问题,请参考以下文章