PL / SQL基于条件插入

时间:2015-03-29 14:07:28

标签: plsql oracle11g

我很感激能得到的所有帮助。我正在学习PL / SQL,偶然发现了一个问题所以请帮我找一个处理这种情况的合适方法:) 我正在运行Oracle 11gR2

我的架构:

CREATE TABLE "ENTRY" 
(
 "TYPE" VARCHAR2(5 CHAR) ,
 "TRANSACTION" VARCHAR2(5 CHAR),
 "OWNER" VARCHAR2(5 CHAR)
);

CREATE TABLE "VIEW" 
(
 "TYPE" VARCHAR2(5 CHAR) ,
 "TRANSACTION" VARCHAR2(5 CHAR),
 "OWNER" VARCHAR2(5 CHAR)
);

CREATE TABLE "REJECTED" 
(
 "TYPE" VARCHAR2(5 CHAR) ,
 "TRANSACTION" VARCHAR2(5 CHAR),
 "OWNER" VARCHAR2(5 CHAR)
);

我的示例数据:

insert into entry (type, transaction, owner) values (11111, 11111, 11111);
insert into entry (type, transaction, owner) values (22222, 22222, 22222);

现在对于令人费解的部分,我已经编写了这个程序,如果特定(事务AND所有者)组合不存在记录,则应该将值从ENTRY表复制到VIEW表。如果VIEW表中存在这样的组合,那么该记录应该转到REJECTED表。这个过程可以做到这一点,但是在多次运行的过程中,我在REJECTED表中获得了越来越多的条目,所以我的问题是如何限制REJECTED表中的插入 - 如果REJECTED表中已经存在记录则不执行任何操作。

create or replace PROCEDURE COPY AS         

v_owner_entry ENTRY.owner%TYPE;
v_transaction_entry ENTRY.transaction%TYPE;

v_owner VIEW.owner%TYPE;
v_transaction VIEW.transaction%TYPE;

begin 

begin 

select e.owner, e.transaction, v.owner, v.transaction 
into v_owner_entry, v_transaction_entry, v_owner, v_transaction
from entry e, view v
where e.owner = v.owner
and e.transaction = v.transaction;

EXCEPTION
when too_many_rows
then
  insert into REJECTED
  (
    TYPE,
TRANSACTION,
OWNER
  )
  SELECT
    s1.TYPE,
    s1.TRANSACTION,
    s1.OWNER
    FROM ENTRY s1;


when no_data_found
THEN

insert into VIEW
    (
      TYPE,
  TRANSACTION,
  OWNER
    )
    SELECT
      s.TYPE,
  s.TRANSACTION,
  s.OWNER
      FROM ENTRY s;

 end;
 end;

有什么建议吗? :)

干杯!

更新 对不起,如果原帖不够清楚 - 该过程应该(从每天)将数据从DB1复制到DB2,并根据条件插入到VIEW或REJECTED中。这是一张照片,也许会更清楚: enter image description here

3 个答案:

答案 0 :(得分:2)

我认为Dmitry试图建议在异常处理程序的too_many_rows情况下使用MERGE 。因此,您已经预先完成了SELECT并确定Entry行出现在View表中,因此它会引发异常too_many_rows。

问题在于您不知道哪些记录引发了异常(假设您的Entry表有多个行容易调用此过程)。因此,我认为您使用异常部分确定行数太多的想法很优雅,但不足以满足您的需求。

作为一名熟练的程序员,我不会试图想出一些非常优雅的东西,而是使用更强大的力量。

更像是:

BEGIN
    FOR entry_cur IN
        (select e.owner, e.transaction, SUM(NVL2(v.owner, 1, 0)) rec_count
           from entry e, view v
          where e.owner = v.owner(+)
            and e.transaction = v.transaction(+)
         GROUP BY e.owner, e.transaction)
    LOOP
        CASE WHEN rec_count > 0
             THEN INSERT INTO view
             ELSE MERGE INTO rejected r
                     ON (r.transaction = entry_cur.transaction
                    AND r.owner = entry_cur.owner)
                   WHEN NOT MATCHED THEN INSERT blah blah blah
        ;
    END LOOP;
END;

HAVING COUNT(*)> 1会 没有例外。循环为您提供了不想插入View的正确记录。顺便说一句,我无法克服您使用对象名称的关键字 - 视图,事务等。您在CREATE TABLE" VIEW"中提出了表名。声明,它解决了这些是关键字的事实,但是当你稍后引用它们时你并没有这样做,所以我很惊讶编译器没有拒绝代码。我认为这是灾难的一个因素,因为它使调试变得更加困难。我只是希望你这样做是为了这个例子而不是PL / SQL。

就我个人而言,我在使用MERGE语句时遇到了麻烦,因为它似乎并不能保持一致,但很久以前就是Oracle版本,可能是我自己对它应该如何工作的无知。

答案 1 :(得分:1)

使用MERGE声明:

merge into REJECTED r
using ENTRY e
   on (r.type = e.type and
       r.transaction = e.transaction and
       r.owner = e.owner)
 when not matched then insert (type, transaction, owner)
 values (e.type, e.transaction, e.owner)

此查询只会在表REJECTED中插入表type中的transactionownerENTRY}的组合,但这些组合尚未出现。

答案 2 :(得分:1)

你试图将自己编码为你自己模仿的窘境。

表格应包含您的实体。不应该存在一个状态的实体表,另一个状态的实体的另一个表,以及另一个状态的实体的另一个表。你会看到这会导致的问题。

状态可以是一个表的属性(字段或列)。或者规范化为state表,但仍然只有一个实体表。当实体改变状态时,这是通过更新来完成的,而不是从一个表移动到另一个表。