如何为 PL SQL 中的现有表创建唯一 ID?

Posted

技术标签:

【中文标题】如何为 PL SQL 中的现有表创建唯一 ID?【英文标题】:How to create a unique id for an existing table in PL SQL? 【发布时间】:2019-03-18 10:33:24 【问题描述】:

情况是,当我将文件导入数据库时​​,我通常做的第一件事就是为每条记录分配一个唯一的 ID。

我通常在 TSQL 中执行以下操作

ALTER TABLE MyTable
    ADD ID INT IDENTITY(1,1)

我想知道PL SQL中是否有类似的东西?

我的所有搜索结果都包含多个步骤。

然后我想知道 PL SQL 程序员在导入文件后通常对 ID 记录做什么。他们这样做吗? 我识别这些记录的主要目的是在操作/复制后对其进行追溯。

再一次,我知道那里有解决方案,我的进一步问题是 PL SQL 程序员是否真的这样做,或者还有其他替代方法使得这一步在 PL SQL 中不是必需的?

【问题讨论】:

Add a auto increment primary key to existing table in oracle的可能重复 这是一个副本的副本。根据我链接到的帖子,以及它作为副本链接到的帖子,oracle 中没有自动增量列。 您使用哪个数据库(及其版本)? PL SQL 是 Oracle 11,TSQL 是 SQL Server 2012 很多答案都是从创建表开始的,但我的场景是从现有表开始的。 【参考方案1】:

好吧,因为您使用的是 Oracle 11g,所以那里没有 identity 列 - 回到多个步骤。这是一个例子:

我正在创建一个模拟您的导入表的表:

SQL> create table tab_import as
  2    select ename, job, sal
  3    from emp
  4    where deptno = 10;

Table created.

添加 ID 列:

SQL> alter table tab_import add id number;

Table altered.

创建一个用于填充 ID 列的序列:

SQL> create sequence seq_imp;

Sequence created.

更新当前行:

SQL> update tab_import set
  2    id = seq_imp.nextval;

3 rows updated.

创建一个触发器来处理未来的插入(如果有的话):

SQL> create or replace trigger trg_bi_imp
  2    before insert on tab_import
  3    for each row
  4  begin
  5    :new.id := seq_imp.nextval;
  6  end;
  7  /

Trigger created.

检查当前表格中的内容:

SQL> select * from tab_import;

ENAME      JOB              SAL         ID
---------- --------- ---------- ----------
CLARK      MANAGER         2450          1
KING       PRESIDENT       5000          2
MILLER     CLERK           1300          3

让我们导入更多行:

SQL> insert into tab_import (ename, job, sal)
  2    select ename, job, sal
  3    from emp
  4    where deptno = 20;

3 rows created.

触发器默默地填充了 ID 列:

SQL> select * From tab_import;

ENAME      JOB              SAL         ID
---------- --------- ---------- ----------
CLARK      MANAGER         2450          1
KING       PRESIDENT       5000          2
MILLER     CLERK           1300          3
SMITH      CLERK            800          4
JONES      MANAGER         2975          5
FORD       ANALYST         3000          6

6 rows selected.

SQL>

很快:你需要

更改表并添加 ID 列 创建序列 创建触发器

结束。

【讨论】:

这看起来像是标准解决方案。感谢您的示例,并在最后进行总结。【参考方案2】:

@Littlefoot 给出的答案也是我的建议 - 但我仍然认为我可以提及以下变体,该变体仅在您以后不打算向表中添加更多行时才有效。

ALTER TABLE MyTable add id number(38,0); 
update MyTable set id = rownum;
commit;  

我的测试:

SQL> create table tst as select * from all_tables; 

Table created.

SQL> alter table tst add id number(38,0);  

Table altered.

SQL> update tst set id = rownum; 

3815 rows updated.

SQL> alter table tst add constraint tstPk primary key (id); 

Table altered.
SQL> 
SQL> select id from tst where id < 15; 

    ID
----------
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11

    ID
----------
    12
    13
    14

14 rows selected.

但正如最初提到的那样,这仅修复了更新时您拥有的行的编号 - 您不会在以后的任何时候为新行获取新的 id 值 - 如果您需要,请按顺序执行解决方案。

【讨论】:

这就是我想要找到的。我无意在这些表上插入更多记录。导入它们后,我的主要任务是在每一行上附加更多属性,有时将其复制到单独的表中以进行其他处理。这就是为什么 ID 过程对于追踪源头对我来说很重要。谢谢!!【参考方案3】:

您可以使用单个语句将 id 列添加到表中(Oracle 11g,请参阅dbfiddle):

alter table test_
add id raw( 16 ) default sys_guid() ;

例子:

-- create a table without an id column
create table test_ ( str )
as
select dbms_random.string( 'x', 16 )
from dual
connect by level <= 10 ;

select * from test_ ;

STR
ULWL9EXFG6CIO72Z
QOM0W1R9IJ2ZD3DW
YQWAP4HZNQ57C2UH
EETF2AXD4ZKNIBBF
W9SECJYDER793MQW

alter table test_
add id raw( 16 ) default sys_guid() ;

select * from test_ ;

STR                     ID
ULWL9EXFG6CIO72Z    0x782C6EBCAE2D7B9FE050A00A02005D65
QOM0W1R9IJ2ZD3DW    0x782C6EBCAE2E7B9FE050A00A02005D65
YQWAP4HZNQ57C2UH    0x782C6EBCAE2F7B9FE050A00A02005D65
EETF2AXD4ZKNIBBF    0x782C6EBCAE307B9FE050A00A02005D65
W9SECJYDER793MQW    0x782C6EBCAE317B9FE050A00A02005D65

测试

-- Are the id values unique and not null? Yes. 
alter table test_ 
add constraint pkey_test_ primary key ( id ) ;

-- When we insert more rows, will the id be generated? Yes.
begin 
  for i in 1 .. 100
  loop
    insert into test_ (str) values ( 'str' || to_char( i ) ) ;
  end loop ;
end ;
/

select * from test_ order by id desc ;
-- last 10 rows of the result
STR ID
str100  0x782C806E16A5E998E050A00A02005D81
str99   0x782C806E16A4E998E050A00A02005D81
str98   0x782C806E16A3E998E050A00A02005D81
str97   0x782C806E16A2E998E050A00A02005D81
str96   0x782C806E16A1E998E050A00A02005D81
str95   0x782C806E16A0E998E050A00A02005D81
str94   0x782C806E169FE998E050A00A02005D81
str93   0x782C806E169EE998E050A00A02005D81
str92   0x782C806E169DE998E050A00A02005D81
str91   0x782C806E169CE998E050A00A02005D81

关于您的其他问题:

1 然后我想知道 PL SQL 程序员在导入文件后通常对 ID 记录做什么。他们这样做吗?我识别这些记录的主要目的是在操作/复制后对其进行追溯。

-> 如您所知,id 的用途是:标识一行。我们不会“对 ID 做任何事情”。因此,您对 ID 的使用似乎是合法的。

2 同样,我知道那里有解决方案,我进一步的问题是 PL SQL 程序员是否真的这样做了,或者还有其他替代方法使得这一步在 PL SQL 中不是必需的?

-> 不太清楚你在这里问什么。虽然有一个 ROWID() 伪列(参见documentation),但我们不应该使用它来识别行。

"你不应该使用 ROWID 作为表的主键。如果你删除 并使用导入和导出实用程序重新插入一行,例如, 那么它的rowid可能会改变。如果你删除一行,那么 Oracle 可能 将其 rowid 重新分配给稍后插入的新行。”

【讨论】:

以上是关于如何为 PL SQL 中的现有表创建唯一 ID?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 PL/SQL 中的 dbms 输出打印的值提供别名?

如何为 Cosmos DB 集合中的列创建唯一键?

如何为mysql中的现有表创建索引?

如何为 django 中的每个匿名用户提供一些唯一的 id

如何用 pl/sql 中的记录项初始化数组?

如何为 MongoDB 中的嵌入式文档创建唯一 ID?