【问题标题】:Stored procedure doesn't have the same result when calling from PL/SQL developer and SQL*plus从 PL/SQL 开发人员和 SQL*plus 调用时,存储过程的结果不同
【发布时间】:2020-05-22 16:44:30
【问题描述】:

我正在尝试使用 sql*plus 从 shell 脚本调用一个过程,但我遇到了一个奇怪的问题。

我的过程首先将数据从表中加载到游标中。 然后,对于游标的每一行,它调用另一个应该将数据插入另一个表的过程。之后,它会更新从第一个表中读取的行以包含“工作完成”时间戳。

当我从 PL/SQL Developer 调用此过程时,一切正常,我将数据放入第二个表中。 当我从 sql*plus 调用相同的过程时,它告诉我一切正常(返回 0),添加了“工作完成”时间戳,但我没有将数据插入到第二个表中。

我不知道是什么原因造成的。

这是脚本中用于调用过程的行:

echo exit | sqlplus -S $schema @call_to_procedure.sql 

$schema 是 schema/pwd@db

call_to_procedure.sql 是

set serveroutput on feedback off
declare
  V_RETURN number(1);
begin
  SCHEMA.PACKAGE.PROCEDURE(V_RETURN);
  dbms_output.put_line(V_RETURN);
end;
/

这里是过程代码(希望我没有删除太多,但基本上没有的是光标的选择查询的过滤器)

PROCEDURE MYPROC (v_result out NUMBER) IS
    v_id_smth number(10);
    v_id_smthelse number(10);
    v_data varchar2(10);
    v_errmsg CLOB;

    CURSOR data_to_load IS
        SELECT t1.id_smth as id_smth, t1.data as data, t2.smthelse as smthelse
        FROM t1, t2
        WHERE t1.id_smth = t2.id_smth
        AND other controls
    ;

BEGIN
    FOR data in data_to_load
    LOOP
        v_id_smth := data.id_smth;
        v_id_smthelse := data.id_smthelse;
        v_data := data.data; -- sorry about that renaming scheme :/

        BEGIN
            INSERT_DATA_INTO_OTHER_TABLE(v_id_smth, v_id_smthelse, v_data);
        END;
    END LOOP;

    UPDATE T1
    SET date_processing = SYSDATE
    WHERE date_processing IS NULL;

    v_result = 0;

EXCEPTION
    WHEN OTHER THEN
    v_errmsg := SQLCODE || '-' || SQLERRM || '; v_id_smth : ' || v_id_smth || '; v_id_smthelse : ' || v_id_smthelse;
    LOG_PACKAGE.LOG_PROC('MY_PROC', v_errmsg);
    v_result := 1;

END MYPROC;

编辑澄清: 这两个过程都在同一个架构/包中,并且我在两个实例中都以架构所有者身份登录(PL Developper 和 sql*plus)。

【问题讨论】:

    标签: bash oracle stored-procedures sqlplus


    【解决方案1】:

    问题很可能出在环境变量和国家日历设置上。 这是一个简单的例子,当星期是 4 或 5 时,取决于国家日历。 比如bat文件

    set NLS_LANG=AMERICAN_RUSSIA.CL8MSWIN1251
    (
    echo  connect  / as sysdba
    echo  @E:\upwork\stackoverflow\bat_sql\sqltest.sql
    echo exit
    )| sqlplus   /nolog
    

    E:\upwork\stackoverflow\bat_sql\sqltest.sql

    select to_char(sysdate,'D') from dual;
    

    输出

    SQL*Plus: Release 11.2.0.4.0 Production on Thu Feb 6 22:53:20 2020
    
    Copyright (c) 1982, 2013, Oracle.  All rights reserved.
    
    SQL> Connected.
    
    
    SQL>
    T
    -
    4
    

    在 NLS_LANG 中更改为 AMERICA

    set NLS_LANG=AMERICAN_AMERICA.CL8MSWIN1251
    (
    echo  connect  / as sysdba
    echo  @E:\upwork\stackoverflow\bat_sql\sqltest.sql
    echo exit
    )| sqlplus   /nolog
    

    E:\upwork\stackoverflow\bat_sql\sqltest.sql

     select to_char(sysdate,'D') from dual;
    

    输出:

    SQL*Plus: Release 11.2.0.4.0 Production on Thu Feb 6 22:56:42 2020
    
    Copyright (c) 1982, 2013, Oracle.  All rights reserved.
    
    SQL> Connected.
    
    SQL>
    T
    -
    5
    

    【讨论】:

    • 嗯,当我从 shell 执行我的程序时,我得到的唯一东西是一个日期,这是正确的,所以我认为不是这样。这个问题似乎不仅仅是游标的加载,让它为空,所以我对游标数据的循环没有做任何事情。我的过程中的第二个查询只是对特定日期字段中没有数据的所有行进行大规模更新以添加这些日期,这是正确执行的。
    • 移除where子句`WHERE t1.id_smth = t2.id_smth AND other controls`中的所有隐式类型转换,并进行显式类型转换。
    • 添加 ALTER SESSION SET NLS_NUMERIC_CHARACTERS=',.'或'.,'
    【解决方案2】:

    另一种选择,您在 SQLPlus 上登录的人是否与 SQLDeveloper 相同?如果一个过程是使用 INVOKER RIGHTS 创建的,执行它的不同用户帐户可能会根据他们的权限产生不同的结果 - 这可能并不明显,尤其是在过程抑制异常时。

    【讨论】:

    • 是的,对不起,我应该在 OP 中这么说,但我以同一个用户(架构/包的所有者)身份登录,所以不幸的是不是这样。两个过程(在 shell 脚本中调用的过程和由第一个过程调用的过程都在同一个模式中,具有相同的权限,并设置为在单独的表中记录异常,该表仍然相当空。
    猜你喜欢
    • 2012-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多