【问题标题】:Oracle - Set the sequence value to max indentity value of the table within triggerOracle - 将序列值设置为触发器内表的最大标识值
【发布时间】:2014-10-30 03:15:15
【问题描述】:

我需要从表中获取最大标识值并将序列设置为该值。

为此,我试图从该触发器中的表(触发当前触发器)中读取最大标识值并将序列设置为该值 但是我在阅读表格时遇到了变异错误。我正在使用 Oracle 11g。

所以我的问题是有什么方法可以将序列值设置为该触发器内表的最大标识值?请指教。

这是我的触发器;

create or replace
TRIGGER StringTextTrg BEFORE INSERT ON StringText
FOR EACH ROW
DECLARE 
v_newVal NUMBER(12) := 0;
v_incval NUMBER(12) := 0;
BEGIN
 IF INSERTING AND :new.STxtID IS NULL THEN
 SELECT  StringText_STxtID_SEQ.NEXTVAL INTO v_newVal FROM DUAL;
 -- If this is the first time this table have been inserted into (sequence == 1)
 IF v_newVal = 1 THEN 
  --get the max indentity value from the table
  SELECT NVL(max(STxtID),0) INTO v_newVal FROM StringText;
  v_newVal := v_newVal + 1;
  --set the sequence to that value
  LOOP
       EXIT WHEN v_incval>=v_newVal;
       SELECT StringText_STxtID_SEQ.nextval INTO v_incval FROM dual;
  END LOOP;
  END IF;
 -- assign the value from the sequence to emulate the identity column
 :new.STxtID := v_newVal;
 END IF;
END;

【问题讨论】:

  • 为什么要从触发器中执行此操作?如果您将代码从手动设置 ID 更改为从序列设置,那么在定义序列时使用正确的起始值是一项一次性任务?
  • @Alex - ID 是否可以通过代码手动设置。我只是想同时满足这两种情况。有什么建议吗?
  • 您的IF v_newVal = 1 THEN 意味着它只会尝试检查最大值并调整序列是新的。我的建议是不允许这两种方法,这不是很有帮助,但会为您节省很多痛苦;但这与您所要求的不同,除非您允许手动值可能高于序列值(而不是填补空白,即使这通常也是一个坏主意)。
  • 是的,亚历克斯,我认为最好的办法是不允许手动输入,我们不能同时满足两者。

标签: oracle triggers sequence


【解决方案1】:

以下是我的回答,我强烈反对使用它:

CREATE OR REPLACE TRIGGER StringTextTrg
    BEFORE INSERT
    ON StringText
    FOR EACH ROW
DECLARE
    v_newVal   NUMBER (12) := 0;
    v_incval   NUMBER (12) := 0;
BEGIN
    IF INSERTING AND :new.STxtID IS NULL THEN
        SELECT StringText_STxtID_SEQ.NEXTVAL INTO v_newVal FROM DUAL;

        -- If this is the first time this table have been inserted into (sequence == 1)
        IF v_newVal = 1 THEN
            --get the max indentity value from the table
            SELECT NVL (MAX (STxtID), 0) INTO v_newVal FROM StringText;

            v_newVal := v_newVal + 1;

            --set the sequence to that value
            EXECUTE IMMEDIATE ('DROP SEQUENCE StringText_STxtID_SEQ');
            EXECUTE IMMEDIATE ('CREATE SEQUENCE StringText_STxtID_SEQ START WITH '||to_char(v_newVal));
        END IF;

        -- assign the value from the sequence to emulate the identity column
        :new.STxtID := v_newVal;
    END IF;
END;
/

序列是数据库对象。您无法重置它们,您必须删除并重新创建它们。因此,您必须(ab)使用动态 SQL 来完成这项工作。

这不是创建自动生成的顺序整数主键列值的最佳做法。此外,请考虑禁止手动输入此列,因为这些肯定会按照您试图维护的顺序造成混乱。

【讨论】:

  • 问题实际上出在此处:'SELECT NVL (MAX (STxtID), 0) INTO v_newVal FROM StringText;'这会引发变异错误。未设置序列值。但我尊重你禁止手动输入的想法。
  • 然后您可以尝试创建一个复合触发器,将上述查询放在语句级别部分并在行级别查询中使用该变量。您使用哪个版本的 Oracle?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-28
  • 2011-10-07
  • 1970-01-01
  • 2021-10-15
  • 2014-08-13
相关资源
最近更新 更多