存储过程不返回受影响的行

时间:2014-03-07 02:29:39

标签: sql-server tsql stored-procedures

这是(确切地说)我的一个存储过程。它在执行时不会返回受影响的行。所以我尝试运行整个查询,提供参数的给定值,然后返回一(1)个受影响的行。我想知道为什么它在存储过程中不会返回受影响的行。我还删除了SET NOCOUNT ON,这样就不会阻止额外的结果集干扰SELECT语句。请帮忙。

这是执行语句

exec STOREPROCEDURENAME @levelnumber=1,@laborlevelid=7,@laborlevelreferenceid=0
go

和存储过程的内容

@levelnumber int = 0, 
@laborlevelid int = 0,
@laborlevelreferenceid int = 0

UPDATE LaborLevelReference SET
        LaborLevelID1 = (CASE WHEN @levelnumber = 0 THEN @laborlevelid ELSE LaborLevelID1 END),
        LaborLevelID2 = (CASE WHEN @levelnumber = 1 THEN @laborlevelid ELSE LaborLevelID2 END),
        LaborLevelID3 = (CASE WHEN @levelnumber = 2 THEN @laborlevelid ELSE LaborLevelID3 END),
        LaborLevelID4 = (CASE WHEN @levelnumber = 3 THEN @laborlevelid ELSE LaborLevelID4 END),
        LaborLevelID5 = (CASE WHEN @levelnumber = 4 THEN @laborlevelid ELSE LaborLevelID5 END),
        LaborLevelID6 = (CASE WHEN @levelnumber = 5 THEN @laborlevelid ELSE LaborLevelID6 END),
        LaborLevelID7 = (CASE WHEN @levelnumber = 6 THEN @laborlevelid ELSE LaborLevelID7 END),
        LaborLevelID8 = (CASE WHEN @levelnumber = 7 THEN @laborlevelid ELSE LaborLevelID8 END),
        LaborLevelID9 = (CASE WHEN @levelnumber = 8 THEN @laborlevelid ELSE LaborLevelID9 END),
        LaborLevelID10 = (CASE WHEN @levelnumber = 9 THEN @laborlevelid ELSE LaborLevelID10 END)
    WHERE LaborLevelReferenceID = @laborlevelreferenceid

2 个答案:

答案 0 :(得分:1)

批量绑定(BULK COLLECT& FORALL)和Oracle中的记录处理

虽然本主题涉及如何针对大型记录集优化数据库DML操作的更大讨论,但此方法适用于不同大小的记录卷,甚至还有一个很好的功能集,其中包含一个名为的DML选项SAVE EXCEPTIONS ,它使数据库操作能够跳过SKIP并继续经历遇到EXCEPTIONS的单个DML事务。

我已经改编了一个脚本,并添加了一些额外的解释性符号来说明这是如何工作的。如果您希望从我使用的来源中获得一些额外的阅读材料,请参阅以下链接,了解有关Oracle DML Bulk Binds and Record Processing的讨论。

样本表:exception_test

使用DDL Below创建用于存储来自我们的过程的批量绑定DML命令的数据的测试表:

CREATE TABLE  "EXCEPTION_TEST" 
   (     "ID" NUMBER(15,0) NOT NULL ENABLE, 
     CONSTRAINT "EXCEPTION_TEST_PK" PRIMARY KEY ("ID") ENABLE
   )
/

主键是单列。它具有一个指定的NOT NULL约束,该约束将是稍后用于生成多个异常的属性。

存储过程:proc_exam_save_exceptions

create or replace PROCEDURE proc_exam_save_exceptions IS

-- Declare and Instantiate Data Types
  TYPE t_tab IS TABLE OF exception_test%ROWTYPE;
  l_tab          t_tab := t_tab();
  l_error_count  NUMBER;

  ex_dml_errors EXCEPTION;
  PRAGMA EXCEPTION_INIT(ex_dml_errors, -24381);

BEGIN

  -- Fill the collection.
  FOR i IN 1 .. 2000 LOOP
    l_tab.extend;
    l_tab(l_tab.last).id := i;
  END LOOP;


  -- Cause a failure or two.
  l_tab(50).id   := NULL;
  l_tab(51).id   := NULL;
  l_tab(1250).id := NULL;
  l_tab(1252).id := NULL;

  EXECUTE IMMEDIATE 'TRUNCATE TABLE exception_test';

  -- Perform a bulk operation.
  BEGIN

    FORALL i IN l_tab.first .. l_tab.last SAVE EXCEPTIONS
      INSERT INTO exception_test
      VALUES l_tab(i);


  EXCEPTION

    WHEN ex_dml_errors THEN
      l_error_count := SQL%BULK_EXCEPTIONS.count;
      DBMS_OUTPUT.put_line('Number of failures: ' || l_error_count);
      FOR i IN 1 .. l_error_count LOOP

        DBMS_OUTPUT.put_line('Error: ' || i || 
          ' Array Index: ' || SQL%BULK_EXCEPTIONS(i).error_index ||
          ' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));

      END LOOP;
   END;
END;

第一个循环实例化一个集合类型变量(嵌套表)并使用非null值初始化它。请注意此过程的块:

-- Cause a failure or two.
l_tab(50).id   := NULL;
l_tab(51).id   := NULL;
l_tab(1250).id := NULL;
l_tab(1252).id := NULL;

使用NULL值更改索引位置50,51,1250和1252以强制对表 exception_test 上的ID列的表约束执行DML错误。编译此过程并从命令行执行它会在DBMS OUT中显示一条反馈消息,用于标识每次循环迭代的内部计数失败的DML操作...

测试存储过程

调用该过程迭代定义的DML循环并验证BULK EXCEPTION HANDLING功能是否正常工作。

-- Command to Call Procedure

begin
   proc_exam_save_exceptions();
end;

以下是此程序执行的输出:

Number of failures: 4
Error: 1 Array Index: 50 Message: ORA-01400: cannot insert NULL into ()
Error: 2 Array Index: 51 Message: ORA-01400: cannot insert NULL into ()
Error: 3 Array Index: 1250 Message: ORA-01400: cannot insert NULL into ()
Error: 4 Array Index: 1252 Message: ORA-01400: cannot insert NULL into ()

Statement processed.

0.05 seconds

目标表的附加查询显示,在循环迭代过程中引入的DML错误并未中断其他循环及其分配的DML操作的完成。

Sample Verification of Skipped Exception Values

附加说明和讨论

以下是使用 SAVE EXCEPTIONS 批量DML选项时要记住的一些注意事项:

  1. 生成的集合的 error_index 值中的元信息: SQL%BULK_EXCEPTIONS 基于来自初始游标查询的循环迭代计数数据

    即,您仍然需要以某种方式关联循环迭代#51(error_index = 51)中的错误与实际DML目标表中存在的任何标识键对齐。我建议至少在DML游标中仔细一致地使用ORDER BY子句,以便循环迭代始终与相同的索引/键值匹配。

  2. SAVE EXCEPTIONS和BULK DML处理备选方案的功能还有一些额外的扩展,这些扩展可以证明可以提供超过大批量DML操作的传统方法的额外实用程序。其中包括:错误阈值限制(即,在处理预定义数量的DML异常时退出)和批量处理循环大小定义。

答案 1 :(得分:0)

感谢您努力帮助我。但问题不在于查询或存储过程本身。我发现最终的错误是我的愚蠢。我将错误的值传递给参数。

@levelnumber int = 0, 
@laborlevelid int = 0,
@laborlevelreferenceid int = 0

这是我能够跟踪的sql profiler执行语句

exec STOREPROCEDURENAME @levelnumber=1,@laborlevelid=7,@laborlevelreferenceid=0
go

在我的程序功能中,我互换了@levelnumber@laborlevelreferenceid 他们应该是这样的

exec STOREPROCEDURENAME @levelnumber=0,@laborlevelid=7,@laborlevelreferenceid=1
go

存储过程不会返回任何受影响的行,因为没有LaborLevelReferenceID(这是我的主键和自动增量)等于0

毕竟是我的错。谢谢你的努力!