在Oracle表中(例如MYTABLE
,使用数字序列字段作为主键),我必须插入数千行,但其中一些应该已经存在于表中。
当然,我应该尝试使用MERGE
,但我也需要检索所有创建的(插入时)和现有的(更新时)主键。
同样,它应该尽可能快。
以下尝试(伪代码)是唯一的方法吗?感谢。
keys_list = empty array
for each row to merge
do query 'SELECT PK_MYTABLE FROM MYTABLE WHERE PK_MYTABLE = '+row.pk_mytable
==> retrieve key
if found then:
add key to keys_list
else:
do query 'INSERT INTO MYTABLE (PK_MYTABLE, ...) VALUES (SEQ_MYTABLE.NEXTVAL, ...)'
do query 'SELECT SEQ_MYTABLE.CURRVAL FROM DUAL' ==> retrieve key
add key to keys_list
答案 0 :(得分:1)
将MODIFICATION_DATE列添加到表
抓取并保存sysdate。
当你合并更新/插入sysdate的值时。
合并完成后,选择MODIFICATION_DATE = SYSDATE和您的行 有你感兴趣的套装。
答案 1 :(得分:0)
为什么不能为此使用MERGE语句?这正是MERGE的用途。以下是对它的外观的粗略概念......
merge into mytable mt
using
(
select key_field, value_field from sourcetable
) st
on
( mt.key_field = st.key_field )
when matched then update
set mt.value_field = st.value_field
when not matched then insert
( key_field, value_field )
values
( st.key_field, st.value_field )
;
使用MERGE语句很快,因为它是单个语句,Oracle优化器可以使用索引并选择比使用PL / SQL迭代游标更好的解释路径。
答案 2 :(得分:0)
如果从序列生成密钥,那么获取该插入生成的密钥的正常方法是使用returns子句:
declare
v_insert_seq integer;
begin
insert into t1 (pk, c1)
values (myseq.nextval, 'value') returning pk into v_insert_seq;
end;
/
但是,据我所知,merge语句不支持该返回功能。
根据新行的来源,您可以通过不同的方式执行此操作。如果你一次插入一行,那么上面的方法就可以了。
要检测重复记录,只需在插入时捕获异常(当dup_val_on_index时),然后使用更新处理它们。
如果您的行源是另一个表,您可能希望查看批量插入,并允许Oracle返回一组新的PK值。我尝试了这个,但是无法让它工作,所以也许它不受支持(或者我今天遗漏了一些东西 - 它给出了语法错误):
declare
type t_type is table of t1.pk%type;
v_insert_seqs t_type;
begin
insert into t1 (pk, c1)
select level newpk, 'value' c1value
from dual
connect by level <= 10 returning pk bulk collect into v_insert_seqs;
exception
when dup_val_on_index then
raise;
end;
/
接下来最好的事情是将行选择到数组中,然后使用bulk绑定和returns子句捕获新的PK ID,并使用Save Exceptions来捕获所有未能插入的行。然后您可以处理之后插入的任何失败:
set serveroutput on
declare
type t_pk is table of t1.pk%type;
type t_c1 is table of t1.c1%type;
v_pks t_pk;
v_c1s t_c1;
v_new_pks t_pk;
ex_dml_errors EXCEPTION;
PRAGMA EXCEPTION_INIT(ex_dml_errors, -24381);
begin
-- get the batch of rows you want to insert
select level newpk, 'value' c1
bulk collect into v_pks, v_c1s
from dual connect by level <= 10;
-- bulk bind insert, saving exceptions and capturing the newly inserted
-- records
forall i in v_pks.first .. v_pks.last save exceptions
insert into t1 (pk, c1)
values (v_pks(i), v_c1s(i)) returning pk bulk collect into v_new_pks;
exception
-- Process the exceptions
when ex_dml_errors then
for i in 1..SQL%BULK_EXCEPTIONS.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;
/
答案 3 :(得分:0)
如果您运行的是Oracle 10或更高版本,您可以通过在合并之前发出提交来更新SCN,然后在合并之后,几乎可以做同样的事情。 使用ORA_ROWSCN来检测哪些行已更改。