它可能指的是 PL/pgSQL 变量或表列。

44

我在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

5
错误信息已经解释了一切:您有一个与参数同名的列。为避免歧义,您需要更改参数的名称。 - user330315
1
@a_horse_with_no_name,您的评论应该是一个答案而不是一个评论。请将其发布为答案。 - Rahul
这个回答是否解决了你的问题?Postgresql列引用“id”不明确 - TylerH
2个回答

66
在这种情况下,当代码足够简单明了时,有时候在函数文本开头依靠其中一个特殊的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非常有用。

34

SQL 标识符和 PlpgSQL 变量发生了冲突。现在没有清晰的解决方案,你需要怎么做呢?你写了一个断言,但它总是为 TRUE。

可以采用以下方法:

  • 为局部变量添加前缀(通常是“_”)
  • 在嵌入式 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;

6
我个人不太喜欢在变量名前加下划线前缀 - 它有点难以注意到,并且在阅读大量代码时可能会造成困惑。我更喜欢一个更加显眼的前缀,比如 p_。(不过,无论如何,答案当然是正确的)。 - Mureinik
匈牙利命名法在这里没有意义。但是良好的命名很重要。为主键和外键选择合适的命名可以简化编写和阅读查询的过程。 - Pavel Stehule
2
一个干净的API不会篡改参数名称,这就是为什么重命名参数以避免冲突的做法实际上是一种不好的做法。在pl/pgsql代码中使用限定名称更好。 - filiprem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接