【问题标题】:Stored Function in Oracle not Inserting Values into the desired tableOracle中的存储函数未将值插入所需的表中
【发布时间】:2015-09-10 19:53:06
【问题描述】:

这是我下面给出的代码。我正在尝试将函数接受的 5 个参数添加到表 Employee 中。但是我做的并不成功,尝试了很多东西。

错误

ORA-01858:在数字所在的位置发现了一个非数字字符 预期的 ORA-06512:在“xxxxxxx.A1SF_ADDEMP”,第 14 行 01858. 00000 - “在需要数字的地方发现了一个非数字字符” *原因:使用日期格式模型转换的输入数据是 不正确。输入数据不包含数字 格式模型所要求的。 *行动:修复输入数据或日期格式模型,以确保 元素在数量和类型上匹配。然后重试操作。

另外,如何测试包含插入/更新或删除语句的存储函数?

执行声明

Select A1SF_ADDEMP('Adesh', '33', 'M', 8000, '26/03/1990')
From dual;

代码

CREATE OR REPLACE Function A1SF_ADDEMP
        (pEmpName In Varchar2,
        pTaxFileNo In Varchar2,
        pGender In Varchar2,
        pSalary In Number,
        pBirthdate In Varchar2
        ) Return Varchar2
        Is
          tEmpId Number(38,0);
          tBirthDate Date;

        BEGIN
              tEmpId := A1Seq_Emp.nextval;
              tBirthdate := to_date('pBirthdate','dd/mm/yyyy');

               Insert Into Employee(EmpId, EmpName, TaxFileNo, Gender, Salary, Birthdate)
                Values (tEmpId, pEmpName, pTaxFileNo, pGender, pSalary, tBirthdate);                 
                Commit;
                Return null;
        END;

【问题讨论】:

    标签: sql oracle function


    【解决方案1】:

    首先,您不能在 select 语句中调用带有 DML 的函数。您必须将输出分配给 PL/SQL 块中的变量,例如:

    declare
      l_output number;
    begin
      l_output := my_function(variable1, variable2);
    end;
    

    在函数中进行 DML 是不好的做法;部分原因是它会导致您遇到的错误。您应该使用如下详述的程序。另一个原因是你总是返回 null 根本不需要返回任何东西!

    create or replace procedure my_procedure ( <variables> ) is
    begin
    
       insert into employees( <columns> )
       values ( <values > );
    
    end;
    

    您的错误的具体原因是这一行:
    tBirthdate := to_date('pBirthdate','dd/mm/yyyy');

    pBirthdate 已经是一个字符串;通过在其周围放置',您将字符串'pBirthdate' 传递给函数to_date,而Oracle 无法将此字符串转换为日、月或年,因此它失败了。

    你应该写成:
    tBirthdate := to_date(pBirthdate,'dd/mm/yyyy');

    你也不需要指定number(38,0),你可以直接写number

    可以使用out 关键字从过程中返回一个值。如果我们假设你想返回empid,你可以这样写:

    create or replace procedure A1SF_ADDEMP (
              pEmpName in varchar2
            , pTaxFileNo in varchar2
            , pGender in varchar2
            , pSalary in number
            , pBirthdate in varchar2
            , pEmpid out number
              ) return varchar2 is
    
    begin
    
       pempid := A1Seq_Emp.nextval;
    
       Insert Into Employee(EmpId, EmpName, TaxFileNo, Gender, Salary, Birthdate)
       Values ( pEmpId, pEmpName, pTaxFileNo, pGender
              , pSalary, to_date(pBirthdate,'dd/mm/yyyy');     
    
    end;
    

    要执行该过程,请像这样调用它:

    begin
    
        A1SF_ADDEMP( EmpName, TaxFileNo, Gender
                   , Salary, Birthdate);
        commit;
    
    end;
    

    如果你想返回empid,那么你可以这样调用它:

    declare
    
       l_empid number;
    
    begin
    
       l_empid := A1SF_ADDEMP( EmpName, TaxFileNo, Gender
                             , Salary, Birthdate);
       commit;
    end;
    

    请注意我是如何将commit 移至最高级别的,这是为了避免在您可能需要做更多事情时在每个过程中提交内容。

    顺便说一句,如果您使用的是 Oracle 11g,则无需将值 A1Seq_Emp.nextval 分配给变量。您可以直接将其插入values 列表中的表中。你当然不能返回它,但你可以返回A1Seq_Emp.curval,只要没有其他东西从序列中获取值。

    【讨论】:

    • 我将如何能够执行上述函数记住 DML 语句我是否必须使用游标或其他东西?
    • @extinguisher33,正如我在回答中解释的那样,您必须将其包装在 PL/SQL 块中;但我会将其转换为一个过程。
    • 程序我知道因为我研究过 SQL Server,但我很想知道我将如何调用,在 Sql 开发人员上测试此函数以及如何从 Visual Studio 调用它;)跨度>
    • @extinguisher33,对不起,我对视觉工作室一无所知;您必须为此提出另一个问题,但如果您想在 SQL-Developer 中执行此操作,您应该能够复制并粘贴我所写的内容。
    【解决方案2】:

    如果您不返回任何值,您应该使用 过程(而不是函数)。

    如果您查看错误消息中提到的行,您可以发现您的错误:

    tBirthdate := to_date('pBirthdate','dd/mm/yyyy');
    

    您正在将 字符串文字 'pBirthdate' 传递给 to_date() 调用。但是你要传参数,所以应该是

    tBirthdate := to_date(pBirthdate,'dd/mm/yyyy');
    

    (注意 pBirthdate 周围缺少的单引号)。

    所以作为一个过程,整个事情看起来像这样:

    CREATE OR REPLACE PROCEDURE A1SF_ADDEMP
            (pEmpName In Varchar2,
            pTaxFileNo In Varchar2,
            pGender In Varchar2,
            pSalary In Number,
            pBirthdate In Varchar2
            )
    IS 
    BEGIN
       Insert Into Employee(EmpId, EmpName, TaxFileNo, Gender, Salary, Birthdate)
       Values (A1Seq_Emp.nextval, pEmpName, pTaxFileNo, pGender, pSalary, to_date(pBirthdate,'dd/mm/yyyy'));
       Commit;
    
    END;
    

    运行它:

    execute A1SF_ADDEMP('Adesh', '33', 'M', 8000, '26/03/1990');
    

    【讨论】:

    • 不能这样执行。从命令中的第 22 行开始出错:执行 A1SF_ADDEMP('Adesh', '33', 'M', 8000, '26/03/1990') 错误报告:ORA-06550:第 1 行,第 7 列:PLS-00221: 'A1SF_ADDEMP' 不是过程或未定义 ORA-06550:第 1 行,第 7 列:PL/SQL:语句被忽略 06550。00000 -“行 %s,列 %s:\n%s” *原因:通常是 PL /SQL 编译错误。 *行动:
    • 这个错误什么时候出现?当您运行 CREATE 语句或运行 EXECUTE 语句时?如果是执行语句,那么您之前是否为了创建过程而不是函数而运行了 CREATE?
    • 只有过程可以这样执行。
    • 你说得对,我给了你创建过程的声明。
    • 那么无论如何我可以将其作为函数执行然后显示结果?
    【解决方案3】:

    在您的情况下,您需要使用带有 out 参数的过程,其中您的 out 参数是包含您想要的值的返回参数。当您想在 select 语句中使用 DML 时,这是我认为在这种情况下的最佳实践。

    第二种方法,但它不是一个好习惯是使用一个像你这样的函数,但在返回一个值之前你需要使用 if 语句来检查值是什么,如果值是你想要在这个 if 中调用的值语句 PRAGMA AUTONOMOUS_TRANSACTION 过程将独立于对它的函数调用来执行您的 DML。有关 pragma 事务的更多信息,您可以在此处阅读: http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/autonotransaction_pragma.htm

    最好的问候,希望我能有所帮助

    【讨论】:

      猜你喜欢
      • 2014-06-04
      • 2013-08-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 2011-08-02
      • 2021-02-22
      相关资源
      最近更新 更多