在简单的 PostgreSQL 函数返回表中避免“歧义列”
Posted
技术标签:
【中文标题】在简单的 PostgreSQL 函数返回表中避免“歧义列”【英文标题】:Avoid 'ambiguous column' in simple PostgreSQL function returning table 【发布时间】:2021-09-27 21:17:42 【问题描述】:假设我有下表,函数和执行:
create table mytable (a INTEGER, b INTEGER);
create function test(q INTEGER)
returns table(a INTEGER, b INTEGER)
as
$body$
begin
return query select a,b from mytable;
end;
$body$
language plpgsql STABLE;
select * from test(1);
我收到“列名不明确”错误。我可以通过将选择更改为“从 mytable t 中选择 t.a, t.b”(根据一些类似的帖子)来摆脱它。但是当我的查询中只有 1 个表时,必须限定列名似乎很奇怪。我正在移植代码,该代码具有从单个表(以各种方式)中选择的大量存储过程并返回具有相同名称的列的表。有没有比这更好的方法来避免错误,并且仍然有一个具有相同列名的输出表?
感谢任何线索。
【问题讨论】:
返回集的schema总是和(a)表一样吗?然后你可以使用... RETURNS SETOF mytable ...
。
@stickybit 好点,至少可以涵盖其中一些 - 尽管定义存储过程的部分原因是确保结果独立于潜在的未来架构更改......所以使用这种方法,它们将再次紧密耦合...
【参考方案1】:
你可以(你应该)使用别名。
create table mytable (a INTEGER, b INTEGER);
create function test(q INTEGER)
returns table(a INTEGER, b INTEGER)
as
$body$
begin
return query select mt.a, mt.b from mytable mt;
end;
$body$
language plpgsql STABLE;
select * from test(1);
【讨论】:
我的问题特别指出了这种解决方法,并询问是否有某种方法可以避免这样做,因为必须在只有一个表的选择上使用别名既麻烦又奇怪。 @Peter - PLpgSQL 内部是非常好的技术。在 PL 之外,没有标识符冲突的风险——因此实际上没有必要在一个表的查询中使用别名。但是在带有嵌入式 SQL 的存储过程中,这种冲突是现实的。使用别名是很好的理由。 除非在 plpgsql 中有一些方法可以让 select 语句在“返回查询”之后引用输出表中的列——如果有的话,我很高兴看到一个例子和一个用例 - 那么不应该有歧义/冲突的可能性,并且解析器不应该抱怨非别名版本。在这里,我还没有看到任何必须使用别名的“充分理由”。 @Peter - 在像这样的简单存储过程中,没有很大的碰撞风险,但是当你有复杂的函数时,这种风险很常见 - 在 plpgsql 变量具有更大优先级的时候(没有检测到碰撞),那么这个错误非常糟糕(真的不可见)。很难找到它。更多 - 像这样的存储过程(只是某些查询的信封)可能是性能反模式。【参考方案2】:也许这是一个选项,使用格式和查询执行: (正如错误所说,它不知道要采用哪个 a,pl/pgSQL 变量或列名)
create function test(q INTEGER)
returns table(a INTEGER, b INTEGER)
as
$body$
declare
lsQueryExecute text;
begin
lsQueryExecute = format('select a,b from mytable');
return query execute lsQueryExecute;
end;
$body$
language plpgsql STABLE;
【讨论】:
这是个坏主意。只有在真正需要的时候,动态 SQL 才是好的。在其他地方没有 - 重复计划的开销很大。以上是关于在简单的 PostgreSQL 函数返回表中避免“歧义列”的主要内容,如果未能解决你的问题,请参考以下文章
在 PostgreSQL 函数中返回时使用 %rowtype