Oracle中不使用触发器实现自增功能

23

除了使用触发器之外,在Oracle中实现自动递增的其他方法是什么?


相关问题:是否可以创建一个序列,然后将nextval方法设置为默认值?即 创建序列seq; 创建表foo(mycol number default seq.nextval); - brofield
9个回答

18

没错。缓存和回滚使这几乎不可能... +1. - Dan Vinton

16

如果您不需要连续的数字,而只需要一个唯一的ID,您可以使用SYS_GUID()函数的默认值。例如:

CREATE TABLE xxx ( ID RAW(16) DEFAULT SYS_GUID() )

11

使用序列获取下一个值的触发器是实现与AUTOINCREMENT等效的最常见方式:

create trigger mytable_trg
before insert on mytable
for each row
when (new.id is null)
begin
    select myseq.nextval into :new.id from dual;
end;

如果您控制插入操作,就不需要触发器 - 只需在插入语句中使用序列:

insert into mytable (id, data) values (myseq.nextval, 'x');

这个可以隐藏在API包内,这样调用者就不需要引用这个序列:

mytable_pkg.insert_row (p_data => 'x');

但是使用触发器更加 "透明"。


触发器只有在:new.id为空时才会生成序列值,这更接近于其他数据库品牌中的自增。 - Bill Karwin
请注意,您需要使用FOR EACH ROW,否则:new将无法访问...或者至少在我上PL/SQL课时我的教科书是这样说的。 - Powerlord

3
据我从我的Oracle工作经验中回忆起来,你无法在没有使用触发器的情况下实现自动递增列。任何实现自动递增列的解决方案都需要使用触发器和序列(我假设你已经知道这一点,因此不再赘述)。

2
当然可以。您可以创建一个获取下一个值的插入存储过程,然后将该表上的插入权限撤销,并授予该过程/包的执行权限。不需要触发器。 - Mark Brady
2
为什么选择了这个答案? - cletus
1
因为这是真的。如果不使用触发器和序列,您无法进行普通的INSERT并实现自动增量的相同效果。Mark Brady的答案也是正确的,如果您将存储过程视为普通插入。 - Salamander2007

3
创建一个序列:
create sequence seq;

然后添加一个值

insert into table (id, other1, other2)
values (seq.nextval, 'hello', 'world');

注意:查找Oracle文档以获取有关序列的更多选项(起始值、增量等)。

2

从12c开始,您可以使用标识列,明确表格和自增之间的链接;无需触发器或序列。语法如下:

create table <table_name> ( <column_name> generated as identity );

0

如果您不想使用“触发器”解决方案,您可以通过编程方法实现自动递增功能,使用getGeneratedKeys()方法获取自动递增键的值。

以下是一个代码片段供您参考:

Statement stmt = null;
ResultSet rs = null;

stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,
                                java.sql.ResultSet.CONCUR_UPDATABLE);

stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTable");

stmt.executeUpdate("CREATE TABLE autoIncTable ("
                + "priKey INT NOT NULL AUTO_INCREMENT, "
                + "dataField VARCHAR(64), PRIMARY KEY (priKey))");

stmt.executeUpdate("INSERT INTO autoIncTable  (dataField) "
                + "values ('data field value')",
                Statement.RETURN_GENERATED_KEYS);

int autoIncKeyFromApi = -1;

rs = stmt.getGeneratedKeys();

if (rs.next()) {
    autoIncKeyFromApi = rs.getInt(1);
}
else {
    // do stuff here        
}

rs.close();

来源:http://forums.oracle.com/forums/thread.jspa?messageID=3368856


0
除了FerranB的回答之外:
值得一提的是,与MySQL中自增长的工作方式相反:
  • 序列在整个数据库范围内工作,因此它们可以用于多个表,且对于整个数据库而言,这些值都是唯一的
  • 因此:截断表不会重置“自增长”功能

  • -8
    SELECT max (id) + 1 
    FROM   table
    

    3
    我认为它不太友好于并发。 - Salamander2007
    我认为它并不是真正的并发友好型。我同意。我见过编写此类代码的Web应用程序做出各种有趣的事情... - RussellH
    这是最糟糕的做法。永远不要使用这样的东西。 - Marius Burz
    3
    如果表格为空,会发生什么? :-( - wonea
    如果表已满会发生什么? ;) - WOUNDEDStevenJones
    如果有两个线程同时执行这个查询会发生什么? - Eki

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接