首页 > 解决方案 > 如果使用触发器出现相同的名称,如何进行增量?

问题描述

我有一张桌子:

id
name
amount

如果name插入了相同的内容,amount则应递增。否则,以 0 金额插入。

如何创建具有给定条件的触发器?

标签: sqloracleplsqloracle11g

解决方案


你真的不应该那样做。AMOUNT列有效地计算NAME了该表中出现的次数。你总能数出来,不是吗?那么,这样做的目的是什么?

如果您想知道在某个其他名称(等于前一个名称)之前(或之后)插入了哪个名称,请按(如果它是增量的,例如标识列或者它是否从序列中获取其值)对它们进行排序。ID

如果ID不是增量,则添加DATE_INSERTED列(并按其排序;或应用按 排序ROW_NUMBER值的分析函数DATE_INSERTED)。

另外,如果您删除其中一个重复名称会怎样?您是否会追溯减少AMOUNT所有先前实例的列NAME


但是,如果你坚持,这里有一个选择。由于您不能只从要插入的表中进行选择(由于 mutating table 错误),因此我使用了复合触发器“插入数量 0”的部分是通过设置列的默认值来完成的(您不需要任何代码)。

SQL> create table test
  2    (id     number primary key,
  3     name   varchar2(20),
  4     amount number default 0);

Table created.

SQL> create or replace trigger trg_ai_test
  2    for insert on test
  3    compound trigger
  4
  5    type test_rt is record (id test.id%type,
  6                            name test.name%type);
  7    type rli_t is table of test_rt index by pls_integer;
  8    g_rli rli_t;
  9
 10  after each row is
 11  begin
 12    g_rli(g_rli.count + 1).id := :new.id;
 13    g_rli(g_rli.count).name := :new.name;
 14  end after each row;
 15
 16  after statement is
 17    l_cnt number;
 18  begin
 19    for i in 1 .. g_rli.count loop
 20      dbms_output.put_Line('x');
 21      dbms_output.put_line(i ||' '|| g_rli(i).id ||' '||g_rli(i).name);
 22      select count(*) into l_cnt
 23        from test
 24        where name = g_rli(i).name;
 25
 26      update test set
 27        amount = l_cnt
 28        where id = g_rli(i).id;
 29    end loop;
 30
 31  end after statement;
 32  end trg_ai_test;
 33  /

Trigger created.

SQL>

测试:

SQL> insert into test (id, name) values (1, 'little');

1 row created.

SQL> insert into test (id, name) values (2, 'foot');

1 row created.

SQL> insert into test (id, name) values (3, 'little');

1 row created.

SQL> insert into test (id, name) values (9, 'little');

1 row created.

SQL> select * from test;

        ID NAME                     AMOUNT
---------- -------------------- ----------
         1 little                        1
         2 foot                          1
         3 little                        2
         9 little                        3

SQL>

或者,一个更简单的解决方案(如上所述),而不使用那么多代码:

SQL> select id, name,
  2    row_number() over (partition by name order by id) as amount
  3  from test;

        ID NAME                     AMOUNT
---------- -------------------- ----------
         2 foot                          1
         1 little                        1
         3 little                        2
         9 little                        3

SQL>

推荐阅读