3

我来自 Microsoft SQL 环境。我有两个表tak_ne,如果值不存在,我的要求是从totak_beb插入值,如果存在则更新。所以我做了一个合并语句,如下所示。面临的是非常天 50000 计数正在增加序列号。Oracle 是稳定的数据库,我不知道他们为什么这样做。所以我创建了一个函数并阻止增加序列号。我的问题是,这是一个正确的方法通过创建函数。以下是我所做的tak_bebtak_ne

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;
4

2 回答 2

3

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 子句,即使语句只更新行,它也会触发(请参阅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)
于 2016-01-02T06:41:34.003 回答
2

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