PostgreSQL复现Oracle复合类型record时嵌套访问报跨库引用错如何解决
错误产生原因
- 你代码中声明的
a_type、b_type、c都是匿名record类型,而非提前定义的强类型复合类型。PL/pgSQL在语法解析阶段无法感知匿名record内部的字段结构,不支持直接通过多级点号访问嵌套属性。 - 当你写
c.sender.infos.name时,PostgreSQL语法解析器会默认把连续多级点号识别为数据库名.模式名.表名.列名的跨数据库引用格式,而PostgreSQL原生不支持跨数据库直接访问,因此抛出cross-database references are not implemented的错误。
解决方案
共有两种可行的修复方式:
方案1:逐层拆包匿名record
不需要修改类型定义,只需要把嵌套的record逐层赋值到单独变量后再访问属性,修改raise notice相关代码即可:
-- 逐层提取嵌套record select (c).sender into b_type; select (b_type).infos into a_type; raise notice '%', a_type.name;
注意:访问record的字段时建议给变量套一层括号,避免解析歧义。
方案2:提前定义全层级强类型复合类型
把所有嵌套层级的结构都提前定义为明确的数据库复合类型,替换原来的匿名record,即可直接通过多级点号访问属性:
- 提前创建所需的嵌套类型:
-- 存储a_table的基础信息 CREATE TYPE infos_type AS ( name varchar, road varchar, zcode varchar, town varchar ); -- 存储发送方信息+联系人数组 CREATE TYPE sender_type AS ( infos infos_type, contacts my_type[] ); -- 最外层包装类型 CREATE TYPE wrapper_type AS ( sender sender_type );
- 修改声明块中的变量类型,替换匿名record:
declare my_cursor cursor (key varchar) for select civility, name, firstname, email, telephone from my_table where sender = key; a_type infos_type; -- 替换原来的record b_type sender_type; -- 替换原来的record c wrapper_type; -- 替换原来的record contact my_type; contacts my_type []; i numeric; begin -- 原有业务逻辑不变 select name, road, zcode, town into strict a_type from a_table; -- 注意你原代码这里缺了分号,需补上 i = 0; open my_cursor (a_type.name); loop fetch my_cursor into contact; exit when not found; contacts[i] = contact; i = i + 1; end loop; select a_type as infos, contacts into strict b_type; select b_type as sender into strict c; -- 现在可以直接访问多级嵌套属性 raise notice '%', c.sender.infos.name; end $$ LANGUAGE 'plpgsql';
内容的提问来源于stack exchange,提问作者mlwacosmos
相关产品推荐
相关产品推荐

