如何更改索引组织表的主键?

Gnu*_*fos 6 oracle

我们从一个简单的主键开始:

SQL> CREATE TABLE books(
        title VARCHAR2(10),
        CONSTRAINT pk_title PRIMARY KEY(title))
      ORGANIZATION INDEX;

Table created.
Run Code Online (Sandbox Code Playgroud)

然后意识到它不是唯一的。比如说,一本书可以以相同的标题重新发行:

SQL> ALTER TABLE books ADD(release_date DATE NOT NULL);

Table altered.
Run Code Online (Sandbox Code Playgroud)

现在要插入重新发布的书,我们必须以某种方式放松标题的唯一性。

但是由于表被索引组织,我无法删除和重新创建 PK:

SQL> ALTER TABLE books DROP PRIMARY KEY;
ALTER TABLE books DROP PRIMARY KEY
*
ERROR at line 1:
ORA-25188: cannot drop/disable/defer the primary key constraint for
index-organized tables or sorted hash cluster
Run Code Online (Sandbox Code Playgroud)

我也无法设法就地扩展现有密钥:

SQL> CREATE UNIQUE INDEX pk_title_date ON books(title, release_date);

Index created.

SQL> ALTER TABLE books MODIFY PRIMARY KEY USING INDEX pk_title_date;
ALTER TABLE books MODIFY PRIMARY KEY USING INDEX pk_title_date
*
ERROR at line 1:
ORA-14196: Specified index cannot be used to enforce the constraint.
Run Code Online (Sandbox Code Playgroud)

我有哪些选择?是否可以不移动数据或重新创建表(实际表很大)?

Mar*_*art 2

索引组织表(IOT)就是这样;没有“真实”表的索引。除主键之外的所有数据都只是“附加”到主键,因此,例如,如果您有一个包含 6 列的 IOT,其中 2 列构成主键,则在幕后您只有一个包含 6 列的索引,其中前两列使其独一无二。

所以,抱歉,解决这个问题的唯一方法是重新创建表;为了缩短重建时间,请暂时禁用日志记录。您不能使用appendIOT 表插入提示来强制直接路径插入:

SQL> CREATE TABLE books_new (
    title VARCHAR2(10),
    release_date DATE NOT NULL,
    CONSTRAINT pk_title PRIMARY KEY(title,release_date))
  ORGANIZATION INDEX NOLOGGING;

SQL> INSERT INTO books_new 
     (SELECT title, '01-Jan-1980' FROM books);
SQL> ALTER TABLE books_new LOGGING;
SQL> ALTER TABLE books RENAME TO books_old;
SQL> ALTER TABLE books_new RENAME TO books;
Run Code Online (Sandbox Code Playgroud)

  • “01-Jan-1980”是字符文字,而不是日期,并且依赖于到“DATE”数据类型的隐式数据类型转换。不要那样做。使用明确的日期文字。`to_date('01-Jan-1980', 'dd-mon-yyyy')` 取决于客户端的 NLS 设置。或者更好的是标准 ANSI SQL 文字:`date '1980-01-01'` (4认同)