Sql oracle中的Merge语句问题

Sql oracle中的Merge语句问题,sql,oracle,sql-merge,Sql,Oracle,Sql Merge,我来自Microsoft SQL环境。我有两个表tak_ne和tak_beb,如果值不存在,我的要求是将值从tak_beb插入tak_ne,如果有,就更新。所以我做了一个如下所示的合并语句。但我现在面临的问题是,每天50000个计数都会增加序列号。Oracle是稳定的数据库,我不知道他们为什么这样做。所以我创建了一个函数并阻止序列号增加。我的问题是,通过创建函数是否是一种正确的方法 merge into tak_ne a using tak_beb b ON (a.NAME=b.NAME) Wh

我来自Microsoft SQL环境。我有两个表
tak_ne
tak_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;

Oracle使用这种方法为语句插入的每一行生成唯一的id。TAK_BEB表可能有50000行,因此序列增加50000倍

将增量隐藏到函数中没有帮助。函数被调用并对每一行执行,它再次将序列递增50000次。它增加了开销,从双表中选择50000个

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

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 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)
现在使用表上的before语句触发器设置变量:

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 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)
Insert触发器有一个缺点——即使语句只更新行,它也会激发with MERGE子句(请参阅)。如果出现问题,则必须以其他方式初始化变量

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

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 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)

在Oracle中,使用自动增量字段的标准方法是使用序列。当然,每次你想使用它时,它都会增加序列号。 但是您可以省略调用
sequence\u 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
    );

我会对你的建议进行研究和开发。虽然我在问题中所做的一切都有助于阻止序列每次递增,直到我插入。但我会以你的方式尝试,这将为每一行使用相同的ID,我不确定OP是否希望这样做。我知道他想避免为每个更新的行生成一个序列,但是每个插入的行应该获得相同的ID还是不同的ID?对,在这种情况下,最好是在触发器中直接使用@Mikhailov-set ID from sequence提供一个解,如果ID在从序列中选择之前不为空,因为MERGE语句为每一行触发update和insert触发器ORACLE 12作为标识列