PLS-00307或参数命令有关系吗?

时间:2017-09-26 09:56:28

标签: database oracle plsql

我无法理解Oracle DBMS的这种行为。我已经制作了两个PL / SQL类型创建示例。第一个是:

create or replace type TEST_TYPE as object (
    ID                      CHAR(36),
    NAME                    VARCHAR2(117 CHAR),
    IS_DEFAULT              CHAR(1),
    APPLICATION_ORDER       NUMBER(38,0),
    CONSTRUCTOR FUNCTION TEST_TYPE(
        ID                      VARCHAR2,
        NAME                    VARCHAR2,
        APPLICATION_ORDER       NUMBER default 0,
        IS_DEFAULT              VARCHAR2 default 'N'
    ) RETURN SELF AS RESULT
);

CREATE OR REPLACE TYPE BODY TEST_TYPE IS
CONSTRUCTOR FUNCTION TEST_TYPE(
        ID                  VARCHAR2,
        NAME                VARCHAR2,
        APPLICATION_ORDER   NUMBER default 0,
        IS_DEFAULT          VARCHAR2 default 'N'
    ) RETURN SELF AS RESULT IS
    BEGIN
        SELF.ID                  := ID;
        SELF.NAME                := NAME;
        SELF.IS_DEFAULT          := IS_DEFAULT;
        SELF.APPLICATION_ORDER   := APPLICATION_ORDER;

        RETURN;
    END;
END;

declare
   app TEST_TYPE;
begin
    app := TEST_TYPE(
        '00000000-0000-0000-0000-000000000000'
        ,'APP_NAME'
        ,13
        ,'N'
    );
end;

运作良好。但是如果你改变了构造函数参数的顺序:

create or replace type TEST_TYPE as object (
    ID                      CHAR(36),
    NAME                    VARCHAR2(117 CHAR),
    IS_DEFAULT              CHAR(1),
    APPLICATION_ORDER       NUMBER(38,0),
    CONSTRUCTOR FUNCTION TEST_TYPE(
        ID                      VARCHAR2,
        NAME                    VARCHAR2,
        IS_DEFAULT              VARCHAR2 default 'N',
        APPLICATION_ORDER       NUMBER default 0
    ) RETURN SELF AS RESULT
);

CREATE OR REPLACE TYPE BODY TEST_TYPE IS
CONSTRUCTOR FUNCTION TEST_TYPE(
        ID                  VARCHAR2,
        NAME                VARCHAR2,
        IS_DEFAULT          VARCHAR2 default 'N',
        APPLICATION_ORDER   NUMBER default 0
    ) RETURN SELF AS RESULT IS
    BEGIN
        SELF.ID                  := ID;
        SELF.NAME                := NAME;
        SELF.IS_DEFAULT          := IS_DEFAULT;
        SELF.APPLICATION_ORDER   := APPLICATION_ORDER;

        RETURN;
    END;
END;

declare
   app TEST_TYPE;
begin
    app := TEST_TYPE(
        '00000000-0000-0000-0000-000000000000'
        ,'APP_NAME'
        ,'N'
        ,13
    );
end;

此代码将导致PLS-00307错误。这真的很奇怪,因为在我需要更多VARCHAR2和默认值的实例中我必须在最后放置APPLICATION_ORDER变量以避免跟随PLS错误,但是在这个小例子代码中我必须做相反的事情。任何人都可以解释这种行为并告诉我如何避免将来出现错误吗?

1 个答案:

答案 0 :(得分:1)

问题在于您创建自己的构造函数时,几乎(但不完全)与the default constructor具有相同的签名:

  

数据库隐式为您创建的每个用户定义类型定义构造函数方法。构造函数是系统提供的过程,在SQL语句或PL / SQL代码中用于构造类型值的实例。构造函数方法的名称是用户定义类型的名称。您还可以使用 constructor_spec 语法创建用户定义的构造函数。

这也称为the attribute-value constructor

您的代码无需定义自己的构造函数即可运行:

create or replace type TEST_TYPE as object (
    ID                      CHAR(36),
    NAME                    VARCHAR2(117 CHAR),
    IS_DEFAULT              CHAR(1),
    APPLICATION_ORDER       NUMBER(38,0)
);
/

Type TEST_TYPE compiled

declare
   app TEST_TYPE;
begin
    app := TEST_TYPE(
        '00000000-0000-0000-0000-000000000000'
        ,'APP_NAME'
        ,'N'
        ,13
    );
end;
/

PL/SQL procedure successfully completed.

...但如果使用较少的参数调用,则不会获取default值。

在第一个代码块中,您使用不同的签名定义自己的构造函数,因为参数(和数据类型)的顺序与默认值不同。使用该构造函数创建实例时,只有一个匹配,因为number值出现在列表或参数中。

在第二个代码块中,您定义了自己的构造函数,几乎与默认签名相同。当您尝试创建类型的实例时,Oracle能够隐式转换您传递给任一构造函数的参数类型的参数,因此它无法分辨两个构造函数中的哪一个你真打算打电话;并因此抛出PLS-00307错误,因为错误消息"太多的TEST_TYPE'匹配这个电话"是对的。

可以覆盖(或隐藏)默认构造函数but the signature has to match exactly

  

[...]但是,如果用户定义的构造函数的签名与属性值构造函数的签名完全匹配,则用户定义的构造函数会隐藏并因此取代其类型的属性值构造函数。对于要匹配的签名,用户定义的构造函数的参数的名称和类型(在隐式SELF参数之后)必须与该类型的属性的名称和类型相同。用户定义的构造函数的参数模式(隐式SELF参数之后)必须为IN

即。您必须使用char代替varchar2来匹配属性类型:

create or replace type TEST_TYPE as object (
    ID                      CHAR(36),
    NAME                    VARCHAR2(117 CHAR),
    IS_DEFAULT              CHAR(1),
    APPLICATION_ORDER       NUMBER(38,0),
    CONSTRUCTOR FUNCTION TEST_TYPE(
        ID                      CHAR,
        NAME                    VARCHAR2,
        IS_DEFAULT              CHAR default 'N',
        APPLICATION_ORDER       NUMBER default 0
    ) RETURN SELF AS RESULT
);
/

Type TEST_TYPE compiled

CREATE OR REPLACE TYPE BODY TEST_TYPE IS
CONSTRUCTOR FUNCTION TEST_TYPE(
        ID                  CHAR,
        NAME                VARCHAR2,
        IS_DEFAULT          CHAR default 'N',
        APPLICATION_ORDER   NUMBER default 0
    ) RETURN SELF AS RESULT IS
    BEGIN
        SELF.ID                  := ID;
        SELF.NAME                := NAME;
        SELF.IS_DEFAULT          := IS_DEFAULT;
        SELF.APPLICATION_ORDER   := APPLICATION_ORDER;

        RETURN;
    END;
END;
/

Type Body TEST_TYPE compiled

declare
   app TEST_TYPE;
begin
    app := TEST_TYPE(
        '00000000-0000-0000-0000-000000000000'
        ,'APP_NAME'
        ,'N'
        ,13
    );
end;
/

PL/SQL procedure successfully completed.

现在,默认构造函数被用户定义的构造函数隐藏,因此没有混淆。