Oracle批量收集错误PLS-00201

时间:2016-12-13 15:24:55

标签: sql oracle plsql oracle11g

我的以下代码未按预期运行。我收到以下错误:

Error at line 1
ORA-06550: line 20, column 18:
PLS-00201: identifier 'I' must be declared
ORA-06550: line 20, column 9:
PL/SQL: Statement ignored

我的代码:

DECLARE

process_limit  CONSTANT  SIMPLE_INTEGER := 500;

CURSOR c1 IS 
  SELECT * FROM cdtx cx
  WHERE EXISTS (SELECT 1 FROM clmx c
                WHERE c.cid = cx.cid);

TYPE t_c1 IS TABLE OF c1%ROWTYPE;
v_c1 t_c1;

BEGIN
  OPEN c1;
  LOOP
    FETCH c1 BULK COLLECT INTO v_c1 LIMIT process_limit;
    EXIT WHEN v_c1.COUNT = 0;

    BEGIN
      FORALL i IN 1..v_c1.COUNT
        INSERT INTO cdx
          (cid,
           oind,
           tind,
           ot_date)
        VALUES (v_c1(i).cid,
                v_c1(i).new_oind,
                v_c1(i).new_tind,
                v_c1(i).ot_date);
        COMMIT;

        IF  v_c1(i).new_t_amt IS NOT NULL 
        AND v_c1(i).new_t_date IS NOT NULL
        THEN
          INSERT INTO ctx
             (cid,
              t_amt,
              t_date,
              t_id)
          VALUES
             (v_c1(i).cid,
              v_c1(i).new_t_amt,
              v_c1(i).new_t_date,
              '1');
          COMMIT;
        END IF;
    END;
  END LOOP;
END;

光标返回接近10k条记录。我最初有没有oracle的BULK COLLECT功能的工作代码,但我认为BULK COLLECT会更快。我在第20行尝试了IF条件的几种变体而没有成功。我需要评估列new_t_amtnew_t_date并检查它们是否为NOT NULL。只有在NOT NULL INSERT i = (char) System.in.read(); 时才会发生import java.util.Scanner; class WhileExample2{ public static void main(String args[]){ Scanner kb = new Scanner(System.in); char i; int a=100; int b=20; do { System.out.println("select your choice"); System.out.println("---------------------"); System.out.println("(1) Additon"); System.out.println("(2) Subtraction"); System.out.println("(3) Multiplication"); System.out.println("(4) Division"); i = kb.nextLine().charAt(0); }while(i < '1' || i > '4'); //rest of code } } 。谢谢你的帮助。

2 个答案:

答案 0 :(得分:1)

如果您使用光标进行循环,那么您可能会看到通过转移到批量收集来改进,请记住Thorsten在您的问题评论中提到的警告。

但是,您可以在单个insert语句中轻松执行此操作,假设您没有遇到任何限制(我希望没有从ctx.cid到cdx.cid的外键),像这样使用multitable insert

INSERT ALL
  WHEN new_t_amt IS NOT NULL
       AND new_t_date IS NOT NULL THEN
       INTO ctx (cid, t_amt, t_date, t_id) VALUES (cid, new_t_amt, new_t_date, '1')
  WHEN 1 = 1 THEN INTO cdx (cid, oind, tind, ot_date) VALUES (cid, new_oind, new_tind, ot_date)
SELECT *
FROM   cdtx cx
WHERE  EXISTS (SELECT 1
               FROM   clmx c
               WHERE  c.cid = cx.cid);

答案 1 :(得分:1)

PL / SQL是一种直接安装在DBMS中的编程语言。但是,PL / SQL引擎仍必须与SQL引擎“对话”才能执行SQL语句。因此,直接运行SQL语句而不是调用PL / SQL函数总是更快。出于这个原因,Boneist建议使用mutli表插入,应该比你的方法更快。

在一些罕见的情况下,使用单个插入的经典方法可以证明更快。这特别适用于覆盖索引:

CREATE INDEX idx_for_cdx ON cdtx(cid, new_oind, new_tind, ot_date);
CREATE INDEX idx_for_ctx ON cdtx(cid, new_t_amt, new_t_date);

第二个索引中的列顺序可能很重要,因此您可以添加

CREATE INDEX idx_for_ctx2 ON cdtx(new_t_amt, new_t_date, cid);

并查看使用了哪个索引。

INSERT INTO cdx (cid, oind, tind, ot_date) 
  SELECT cid, new_oind, new_tind, ot_date
  FROM cdtx
  WHERE cid IN (SELECT cid FROM clmx);

INSERT INTO ctx (cid, t_amt, t_date, t_id) 
  SELECT cid, new_t_amt, new_t_date, '1'
  FROM cdtx
  WHERE cid IN (SELECT cid FROM clmx)
  AND new_t_amt IS NOT NULL 
  AND new_t_date IS NOT NULL;

COMMIT;

如果您愿意,也可以将它放在匿名的PL / SQL块中:

BEGIN
  INSERT INTO cdx ...
  INSERT INTO ctx ...
  COMMIT;
END;

唯一的区别是,从机器到数据库机器的往返次数会减少,因为这些将被移动到PL / SQL引擎和SQL引擎之间的数据库机器内。