它可以引用 PL/pgSQL 变量或表列

Posted

技术标签:

【中文标题】它可以引用 PL/pgSQL 变量或表列【英文标题】:It could refer to either a PL/pgSQL variable or a table column 【发布时间】:2014-03-06 21:41:52 【问题描述】:

我在 pgsql 中有一个函数

CREATE OR REPLACE FUNCTION core.date_bs_from_ad(date_in_ad date)
  RETURNS character varying AS
$$
BEGIN
    RETURN(
        SELECT date_in_bs FROM core.date_conversion
        WHERE date_in_ad = $1
    );
END
$$

  LANGUAGE plpgsql;

它的创建没有错误,但是当我使用此功能时出现以下错误:

ERROR:  column reference "date_in_ad" is ambiguous
LINE 3:   WHERE date_in_ad = $1
                ^
DETAIL:  It could refer to either a PL/pgSQL variable or a table column.
QUERY:  SELECT (
        SELECT MAX(date_in_bs) FROM core.date_conversion
        WHERE date_in_ad = $1
    )
CONTEXT:  PL/pgSQL function core.date_bs_from_ad(date) line 3 at RETURN
********** Error **********

ERROR: column reference "date_in_ad" is ambiguous
SQL state: 42702
Detail: It could refer to either a PL/pgSQL variable or a table column.
Context: PL/pgSQL function core.date_bs_from_ad(date) line 3 at RETURN

【问题讨论】:

错误信息说明了一切:你有一个列一个同名的参数。您需要更改参数的名称以避免歧义 @a_horse_with_no_name,您的评论应该是答案而不是评论。请将其发布为答案。 【参考方案1】:

在这种情况下,代码足够简单直接,有时在函数文本的开头依赖这些特殊的 plpgsql 命令之一很有用:

#variable_conflict error
#variable_conflict use_variable
#variable_conflict use_column

在这种情况下,它将按如下方式使用:

CREATE OR REPLACE FUNCTION core.date_bs_from_ad(date_in_ad date)
  RETURNS character varying AS
$$
#variable_conflict use_column
BEGIN
    RETURN(
        SELECT date_in_bs FROM core.date_conversion
        WHERE date_in_ad = $1
    );
END
$$

这对于不与参数冲突而是与输出列名称冲突的情况特别有用,例如:

CREATE OR REPLACE FUNCTION core.date_bs_from_ad(p_date_in_ad date)
  RETURNS TABLE (date_in_bs character varying) AS
$$
BEGIN
    RETURN QUERY
        SELECT date_in_bs FROM core.date_conversion
        WHERE date_in_ad = p_date_in_ad;
END;
$$

上面的函数将失败,因为编译器无法确定date_in_bs 是输出变量名称还是core.date_conversion 的列之一。对于此类问题,#variable_conflict use_column 命令确实可以提供帮助。

【讨论】:

【参考方案2】:

SQL 标识符和 PlpgSQL 变量之间存在冲突。没有干净的,你想要什么。你写了一个谓词,它总是正确的。

很好用:

局部变量的前缀(通常是“_”) 嵌入式 SQL 中的限定名称 - 如 table_name.column_name

所以两种技术(只需要一种)

CREATE OR REPLACE FUNCTION core.date_bs_from_ad(_date_in_ad date)
RETURNS character varying AS $$
BEGIN
  RETURN SELECT dc.date_in_bs
             FROM core.date_conversion dc
            WHERE dc.date_in_ad = _date_in_ad;
END
$$  LANGUAGE plpgsql;

对于这些一行函数,SQL语言比较好:

CREATE OR REPLACE FUNCTION core.date_bs_from_ad(_date_in_ad date)
RETURNS character varying AS $$
   SELECT dc.date_in_bs
      FROM core.date_conversion dc
     WHERE dc.date_in_ad = $1; 
$$  LANGUAGE sql;

【讨论】:

我自己不是 _ 前缀的忠实粉丝——这有点难以注意到,并且在阅读大量代码时可能会造成混淆。我更喜欢更显眼的前缀,比如p_。 (无论如何,答案当然是正确的)。 匈牙利公约在这里没有意义。但是好的命名很重要。 PK 和 FK 的智能命名可以简化书写和阅读查询。

以上是关于它可以引用 PL/pgSQL 变量或表列的主要内容,如果未能解决你的问题,请参考以下文章

从 PL/PGSQL 引用会话变量 (\set var='value')

游标可以在 PL/pgSQL 中保存变量吗?

在 PL/PGSQL 动态 SQL 内部函数中引用局部变量

PL/PGSQL - 无法将 SELECT 语句中的 array_agg 分配给变量

在 PL/pgSQL 函数中使用变量

PL/pgSQL:删除(更新)与记录匹配的行