【问题标题】:oracle pl/sql function name resolution errororacle pl/sql 函数名解析错误
【发布时间】:2014-10-23 19:15:42
【问题描述】:

我正在尝试执行一个相当简单的功能。我想将主机名传递给该函数,我希望它获取该主机名并使用它来查找与该主机名关联的系统ID并返回它。

您将在下面看到我有一个 pl/sql 块正在调用一个名为 GET_SYSTEMID 的函数,当我将 varchar 传递给该函数时,我得到了一个错误返回。当我在函数中对相同的字符串进行硬编码时,我得到了正确的结果。保存主机名的列有一个唯一的约束,所以如果我使用我的一台服务器的确切主机名(我确定)应该只有一个匹配的行。

这是我的调用块:

Declare
    sysid number;
Begin
    sysid := Server.GET_SYSTEMID('MyHost');
    DBMS_OUTPUT.PUT_LINE('SYSID is '||sysid);    
END;

如果我使用那个块来调用这个函数它不起作用:

FUNCTION GET_SYSTEMID(Hostname varchar2)
RETURN NUMBER
IS
    SysID number;
BEGIN 
    SELECT mySystems.SYSTEMID
    INTO SysID
    FROM mySystems
    where mySystems.HOSTNAME = Hostname;

    return SysID;
END GET_SYSTEMID;

当我运行上述程序时,我收到以下错误消息:

Declare
    sysid number;
Begin
    sysid := Server.GET_SYSTEMID('MyHost');
    DBMS_OUTPUT.PUT_LINE('SYSID is '||sysid);    
END;
Error at line 3
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "MySchema.Server", line 33
ORA-06512: at line 12

接下来的两个确实可以工作,但是当他们对主机名进行硬编码时,他们不会做我需要这个函数来做的事情:

第一名:

FUNCTION GET_SYSTEMID(Hostname varchar2)
RETURN NUMBER
IS 
    SysID number;
    tmp varchar2(8) := 'MyHost';--should be identical to passed in value
BEGIN 
    SELECT mySystems.SYSTEMID
    INTO SysID
    FROM mySystems
    where mySystems.HOSTNAME = tmp;

    return SysID;
END GET_SYSTEMID;

第二个:

FUNCTION GET_SYSTEMID(Hostname varchar2)
RETURN NUMBER
IS
    SysID number;
BEGIN 

    SELECT mySystems.SYSTEMID
    INTO SysID
    FROM mySystems
    where mySystems.HOSTNAME = 'MyHost';--should be identical to passed in value

    return SysID;
END GET_SYSTEMID;

【问题讨论】:

  • 可能是名称冲突。尝试重命名参数:FUNCTION GET_SYSTEMID(p_Hostname varchar2)
  • 正如 Egor 所说,mySystems.HOSTNAME = Hostname 就像 1=1,所以所有行都返回了! SQL 区分大小写。

标签: oracle function plsql namespaces


【解决方案1】:

问题是名称解析之一。

当您引用的表中有参数hostnamehostname 列时,范围解析规则会导致大多数人混淆。这就是为什么许多人建议对参数和局部变量使用命名约定,以将它们与表名区分开来。例如,在我的代码中,我使用p_ 为参数名称添加前缀,并使用l_ 为局部变量添加前缀。

在你的代码中,当你有

SELECT mySystems.SYSTEMID
INTO SysID
FROM mySystems
where mySystems.HOSTNAME = Hostname;

hostname 被解析为表中的列,而不是参数。这会导致查询返回表中hostname 不为空的每一行,从而导致错误。可以显式在参数名前加上函数名,强制hostname解析为参数

SELECT mySystems.SYSTEMID
INTO SysID
FROM mySystems
where mySystems.HOSTNAME = GET_SYSTEMID.Hostname;

这行得通。但是添加函数名称前缀通常会很烦人。如果您采用前缀参数名称和局部变量名称的约定,您会得到类似

FUNCTION GET_SYSTEMID(p_hostname varchar2)
RETURN NUMBER
IS
    l_sysID number;
BEGIN 
    SELECT mySystems.SYSTEMID
    INTO l_sysID
    FROM mySystems
    where mySystems.HOSTNAME = p_hostname;

    return l_sysID;
END GET_SYSTEMID;

这也有效,而且(在我看来)比到处添加显式函数名称前缀更清晰。

【讨论】:

  • 这个答案是正确的,写得很好。感谢@justin 解释了我在自学 pl/sql 之后没有遇到什么让我感到惊讶的事情。再次感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-15
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多