PL/SQL 根据条件插入
PL/SQL insert based on conditions
如果能得到所有帮助,我将不胜感激。我正在学习 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);
现在对于令人费解的部分,我编写了这个过程,如果特定(交易和所有者)的记录不存在,它应该将值从 ENTRY table 复制到 VIEW table组合。如果这样的组合存在于 VIEW table 中,则该记录应该转到 REJECTED table。这个过程是这样做的,但是在多次运行过程中,我在 REJECTED table 中得到越来越多的条目所以我的问题是如何限制在 REJECTED table 中的插入 - 如果 REJECTED 中已经存在记录table 然后什么也不做。
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;
大家有什么建议吗? :)
干杯!
更新
对不起,如果原来的 post 不够清楚 -
该过程应将数据(每天)从 DB1 复制到 DB2,并根据条件插入到 VIEW 或 REJECTED 中。这是一张照片,也许会更清楚:
使用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)
此查询将仅插入到 table REJECTED
中 table [=] 中的 (type
、transaction
、owner
) 组合15=] 尚不存在。
您正试图通过编码使自己摆脱自己模仿的困境。
A table 应该包含您的实体。不应该有 table 个实体处于一个状态,另一个 table 个实体处于另一个状态,另一个 table 个完全不同状态的实体。您看到了这可能导致的问题。
状态可以是 table 的一个属性(字段或列)。或者标准化为 state
table 但仍然只有一个实体 table。当一个实体改变状态时,这是通过更新来完成的,而不是从一个 table 到另一个的移动。
我认为 Dmitry 试图建议在 异常处理程序的 too_many_rows 情况下使用 MERGE 。所以您已经预先完成 SELECT 并确定条目行出现在您的视图 table 中,因此它引发了异常 too_many_rows。
问题是您不知道哪些记录引发了异常(假设您的条目 table 有不止一行,很容易调用此过程)。所以我认为你使用异常部分来确定你有太多行的想法很优雅,但不足以满足你的需要。
作为熟练的程序员,我不会尝试想出一些非常优雅的东西,而是使用更多的蛮力。
更像是:
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 将
没有抛出异常。该循环为您提供了您不想插入到视图中的正确记录。顺便说一句,我无法忘记你使用关键字作为对象名称——视图、事务等。你在 CREATE TABLE "VIEW" 语句中引用了 table 名称,它绕过了事实上,这些是关键字,但您稍后引用它们时却没有,所以我很惊讶编译器没有拒绝代码。我认为这是灾难的根源,因为它使调试变得更加困难。我只是希望你在这里的例子中这样做,而不是 PL/SQL。
就我个人而言,我在使用 MERGE 语句时遇到了问题,它似乎无法始终如一地工作,但那是很久以前的 Oracle 版本,可能是我自己对它的工作方式一无所知。
如果能得到所有帮助,我将不胜感激。我正在学习 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);
现在对于令人费解的部分,我编写了这个过程,如果特定(交易和所有者)的记录不存在,它应该将值从 ENTRY table 复制到 VIEW table组合。如果这样的组合存在于 VIEW table 中,则该记录应该转到 REJECTED table。这个过程是这样做的,但是在多次运行过程中,我在 REJECTED table 中得到越来越多的条目所以我的问题是如何限制在 REJECTED table 中的插入 - 如果 REJECTED 中已经存在记录table 然后什么也不做。
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;
大家有什么建议吗? :)
干杯!
更新
对不起,如果原来的 post 不够清楚 -
该过程应将数据(每天)从 DB1 复制到 DB2,并根据条件插入到 VIEW 或 REJECTED 中。这是一张照片,也许会更清楚:
使用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)
此查询将仅插入到 table REJECTED
中 table [=] 中的 (type
、transaction
、owner
) 组合15=] 尚不存在。
您正试图通过编码使自己摆脱自己模仿的困境。
A table 应该包含您的实体。不应该有 table 个实体处于一个状态,另一个 table 个实体处于另一个状态,另一个 table 个完全不同状态的实体。您看到了这可能导致的问题。
状态可以是 table 的一个属性(字段或列)。或者标准化为 state
table 但仍然只有一个实体 table。当一个实体改变状态时,这是通过更新来完成的,而不是从一个 table 到另一个的移动。
我认为 Dmitry 试图建议在 异常处理程序的 too_many_rows 情况下使用 MERGE 。所以您已经预先完成 SELECT 并确定条目行出现在您的视图 table 中,因此它引发了异常 too_many_rows。
问题是您不知道哪些记录引发了异常(假设您的条目 table 有不止一行,很容易调用此过程)。所以我认为你使用异常部分来确定你有太多行的想法很优雅,但不足以满足你的需要。
作为熟练的程序员,我不会尝试想出一些非常优雅的东西,而是使用更多的蛮力。
更像是:
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 将 没有抛出异常。该循环为您提供了您不想插入到视图中的正确记录。顺便说一句,我无法忘记你使用关键字作为对象名称——视图、事务等。你在 CREATE TABLE "VIEW" 语句中引用了 table 名称,它绕过了事实上,这些是关键字,但您稍后引用它们时却没有,所以我很惊讶编译器没有拒绝代码。我认为这是灾难的根源,因为它使调试变得更加困难。我只是希望你在这里的例子中这样做,而不是 PL/SQL。
就我个人而言,我在使用 MERGE 语句时遇到了问题,它似乎无法始终如一地工作,但那是很久以前的 Oracle 版本,可能是我自己对它的工作方式一无所知。