ORACLE 始终将标识列保持为一 (1)

ORACLE keep identity columns always as one (1)

我发现了一些与我类似的问题,但找不到确切的解决方案。在我们拥有的数据仓库中,当我们解决某些问题或其他类似问题时,有时会 "Delete" 或 "Truncate" table。但是,在Oracle中,标识列总是从下一个字符串开始,如何让字符串总是从1开始呢?这会扰乱其他维度和事实。

是否可以永远或至少在插入过程中放置​​此配置?

我总是通过 SQL 开发人员手动重置身份列,因为我不知道如何通过 PL/SQL 进行重置,如下所示(软件是葡萄牙语,抱歉)。

创建的标识列示例:

CREATE TABLE "DW_FUNCESP"."D_DEPARTAMENTO"
(
    "ID_DEPARTAMENT" NUMBER(10,0) GENERATED BY DEFAULT ON NULL AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1
    START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE
)

谢谢!


编辑:根据我当时的了解,我是对的,但事实证明我是不正确的。在评论和相关联的 fiddle 中,@micklesh 展示了如何使用 ALTER TABLE MODIFY... 来完成此操作。我已经要求他 post 一个答案以便它可以被接受 - 同时我将这个答案留在这里以便其他人至少可以 follow the link to his dbfiddle。但实际上 - 这是不正确的。


抱歉,您不能这样做。

关于如何获取系统为 GENERATED ALWAYS AS IDENTITY 列创建的序列的名称,以及如何将 LONG 值转换为字符串,以及如何重置序列的起始值 - 所有好东西,和 it made a really nice db<>fiddle - 然后当我把它全部包起来时,我最后一次通过它 - 并得到

ORA-32793: cannot alter a system-generated sequence

因此 - Oracle 不允许您更改它为 GENERATED ALWAYS AS IDENTITY 列生成的序列。我认为这意味着你被困住了,你将不得不忍受这些数字无法重置为从 1 开始的事实。您的其他选择是

  1. 删除并重新创建 table,这还需要您重新创建任何关联的触发器,并重新编译任何使用此 table 的 procedures/functions/packages,并且可能其他我没有想到的;或

  2. 不要使用 GENERATE ALWAYS AS IDENTITY,创建你自己的序列,使用触发器从你的序列中设置标识列,然后 然后 你应该能够使用以下过程来重置您的序列:

CREATE OR REPLACE FUNCTION RESET_SEQUENCE(pinSequence    IN VARCHAR2,
                                          pinStart_value IN NUMBER DEFAULT 1,
                                          pinIncrement   IN NUMBER DEFAULT 1)
  RETURN NUMBER
AS
  nVal  NUMBER;
BEGIN
  -- Get the next value from the sequence

  EXECUTE IMMEDIATE 'SELECT ' || pinSequence || '.NEXTVAL ' ||
                    '  FROM DUAL'
    INTO nVal;

  -- Change the sequence so it decrements or increments to the desired
  -- start value the next time NEXTVAL is invoked.

  EXECUTE IMMEDIATE 'ALTER SEQUENCE ' || pinSequence ||
                    '  INCREMENT BY ' || (nVal - (pinStart_value - pinIncrement)) * -1 ||
                    '  MINVALUE 0';

  -- Decrement/increment the sequence to the desired start value

  EXECUTE IMMEDIATE 'SELECT ' || pinSequence || '.NEXTVAL ' ||
                    '  FROM DUAL'
    INTO nVal;

  -- Reset the sequence so it uses the desired "increment-by"

  EXECUTE IMMEDIATE 'ALTER SEQUENCE ' || pinSequence ||
                    '  INCREMENT BY ' || pinIncrement ||
                    '  MINVALUE 0';

  RETURN 1;
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('RESET_SEQUENCE : ' || SQLCODE || ' ' || SQLERRM);
    RETURN 0;
END RESET_SEQUENCE;
/

And here's a db<>fiddle 显示 RESET_SEQUENCE 函数的一般测试。

注意:

完整示例已准备就绪 ,我只是稍微调整了解决方案以使用 ALTER TABLE 子句(按照约定) 全部归功于@Bob Jarvis


正如评论中已经提到的,Oracle IDENTITY 列仅由系统创建的 SEQUENCE 提供支持。可以找到一些详细信息,例如 here(带有官方 Oracle 文档的正确链接)。

Oracle 没有重置序列值的简单方法,但是 here's 关于如何使用非常简单的步骤进行重置的广泛讨论

不幸的是(尽管可能是幸运的)不允许以这种方式更改系统创建的序列,但是可以通过 运行 ALTER TABLE 更改序列属性修改 个命令。可以在这里看到摘录

BEGIN
  -- Get the next value from the sequence
  EXECUTE IMMEDIATE 'SELECT ' || v_sequence || '.NEXTVAL ' ||
                    '  FROM DUAL'
    INTO v_num;

  -- Change the sequence so it decrements or increments to the desired
  -- start value the next time NEXTVAL is invoked.

  v_sql := 'ALTER TABLE ' || p_table_name || ' MODIFY ('
  || p_column_name || ' GENERATED BY DEFAULT ON NULL AS IDENTITY (INCREMENT BY '
  || (-v_num)  || ' MINVALUE 0))' ;
  EXECUTE IMMEDIATE v_sql;

  -- Decrement/increment the sequence to the desired start value
  EXECUTE IMMEDIATE 'SELECT ' || v_sequence || '.NEXTVAL FROM DUAL'
    INTO v_num;

  -- Reset the sequence so it uses the desired "increment by"
  v_sql := 'ALTER TABLE ' || p_table_name || ' MODIFY ('
  || p_column_name || ' GENERATED BY DEFAULT ON NULL AS IDENTITY (INCREMENT BY 1))' ;
  EXECUTE IMMEDIATE v_sql;
END;
/

以及 dbfiddle

上的完整示例