在oracle中合并语句问题

时间:2016-01-02 05:12:40

标签: sql oracle sql-merge

我来自Microsoft SQL环境。我有两个表tak_netak_beb,如果值不存在,我的要求是将tak_beb的值插入tak_ne,如果它存在只是更新。所以我做了一个合并声明,如下所示。但现在我面临的问题是,当天50000计数正在增加序列号.Oracle是稳定的数据库,我不知道为什么他们做了它所以我创建了一个函数并阻止了递增序列号。我的问题是,通过创建函数是一种正确的方法。以下是我做的事情

merge into tak_ne a using tak_beb b ON (a.NAME=b.NAME)
When matched then
   Update
   Set a.AC_NO = b.AC_NO
       a.LOCATION = b.LOCATION
       a.MODEL = b.MODEL
When not matched then
insert
(
sl_no,
AC_NO,
LOCATION
MODEL
)
Values
(
s_slno_nextval
b.AC_NO
b.LOCATION
b.MODEL
)

然后我创建了一个函数

CREATE OR REPLACE FUNCTION s_slno_nextval
      RETURN NUMBER
    AS
      v_nextval NUMBER;
    BEGIN
      SELECT s_emp.nextval
      INTO   v_nextval
      FROM   dual;
      RETURN v_nextval;
  END;

2 个答案:

答案 0 :(得分:3)

Oracle使用此方法为语句插入的每一行生成唯一ID。您的TAK_BEB表可能有50000行,因此序列增加了50000次。

将增量隐藏到函数中无济于事。对于每一行,函数被称为AND EXECUTED,它再次递增序列50000次。并且它增加了来自双表的50000个选择的开销。

如果您确实需要对语句插入的所有行使用序列中的ONE值,请使用包变量:

create package single_id_pkg is
  id  Number;
  function get_id return number;
end;
/

create or replace package body single_id_pkg is
  function get_id return number is
  begin
    return id;
  end;
end;
/

现在使用例如在表上的语句触发器之前设置变量:

create trigger tak_ne_BSI_trg
before insert
on tak_ne
begin
  select s_emp.nextval
    into single_id_pkg.id
    from dual;
end;

插入触发器有一个缺点 - 即使语句仅更新行,也会触发MERGE子句(请参阅https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:25733900083512)。如果这是一个问题,你必须以其他方式初始化变量。

接下来修改您的语句以使用包变量:

merge into tak_ne a
  using tak_beb b
  on (a.NAME=b.NAME)
when matched then
  update
    set a.AC_NO = b.AC_NO
        a.LOCATION = b.LOCATION
        a.MODEL = b.MODEL
when not matched then
  insert (sl_no,
          AC_NO,
          LOCATION,
          MODEL)
  values (single_id_pkg.get_id
          b.AC_NO,
          b.LOCATION,
          b.MODEL)

答案 1 :(得分:2)

在Oracle标准中使用autoincrement字段的方法是使用序列。当然,每次要使用它时,它都会增加序列号。 但是你可以省略调用sequence_name.nextval,将其隐藏在触发器中它也被认为是标准方法。

CREATE OR REPLACE EDITIONABLE TRIGGER TAK_NE_ID_TR"
BEFORE INSERT ON tak_ne
FOR EACH ROW
BEGIN
IF :old.sl_no IS NULL THEN
  :new.sl_no := s_emp.nextval;
END IF;
END;

如果要为一批插入添加相同的ID,可以使用全局临时表进行保存。例如,像这样:

create global temporary table tak_ne_id ("id" number) on commit delete rows

create or replace trigger tak_ne_BSI_trg
before insert
on tak_ne
begin
 insert into tak_ne_id("id")
 values(s_emp.nextval);
end

create or replace TRIGGER TAK_NE_ID_TR
BEFORE INSERT ON tak_ne
FOR EACH ROW
BEGIN
if :old.sl_no is null then
  SELECT "id"
  INTO   :new.sl_no
  FROM   tak_ne_id;
end if;
END;

然后您可以像以前一样使用合并,而无需调用nextval

 merge into tak_ne a using tak_beb b ON (a.NAME=b.NAME)
    When matched then
       update
       set a.AC_NO = b.AC_NO,
           a.LOCATION = b.LOCATION,
           a.MODEL = b.MODEL
    When not matched then
    insert
    (
    AC_NO,
    LOCATION,
    MODEL
    )
    Values
    (
    b.AC_NO,
    b.LOCATION,
    b.MODEL
    );