我正在尝试执行一个相当简单的功能。我想将一个主机名传递给此函数,我希望它获取该主机名并使用它来查找与该主机名关联的systemID并将其返回。
下面你会看到我有一个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;
答案 0 :(得分:3)
问题是名称解析之一。
当您在表格中引用参数hostname
和hostname
列时,范围解析规则会导致大多数人产生混淆。这就是为什么许多人建议使用参数和局部变量的命名约定来区分它们与表名。例如,在我的代码中,我使用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;
与在整个地方添加显式函数名称前缀相比,这也有效并且(在我看来)更清晰。