1.8.2 序列的使用
对用户而言,序列中的可用资源是其中包含的序号。用户可以通过SELECT命令获得可用的序号,也可以将序号应用于DML语句和表达式中。如果要使用其他用户的序列,则必须具有对该序列的SELECT权限。
序列提供了两个伪列,即NEXTVAL和CURRVAL,用来访问序列中的序号。其中NEXTVAL代表下一个可用的序号,CURRVAL代表当前的序号。序列可以认为是包含了一系列序号的一个指针。序列刚被创建时,这个指针位于第一个序号之前,以后每获得一个序号,指针就向后移动一个位置,这时就可以用CURRVAL访问序列中的当前序号,用NEXTVAL访问下一个序号。在第一次使用序列中的序号时,必须首先访问NEXTVAL伪列,使指针指向第一个序号。图1.4为序列中的序号和指针的示意。
图 1.4 序列中的序号
通过SELECT语句可以从序列中获得一个可用的序号。例如,对于已经创建的序列SEQ1,可以执行下面的SELECT语句:
SQL>SELECT seq1.nextval FROM dual;
这条语句的执行结果为:
NEXTVAL
1
其中seq1.nextval表示序列seq1的NEXTVAL伪列。这时如果再利用SELECT语句访问这个序列的CURRVAL伪列,应该返回它的当前序号,即1。在SELECT语句中使用表dual是必要的,因为SELECT语句将根据表中数据的行数返回若干个序号,并且每访问一次NEXTVAL伪列,指针就向后移动一个序号。假设把SELECT语句中的表名用dept代替,那么执行结果为:
NEXTVAL
2
3
4
5
因为表dept中有四行,所以SELECT语句返回接下来的连续四个序号。
CURRVAL伪列代表序列中的当前序号,访问这个伪列时指针并不向后移动。CURRVAL伪列的引用方法与NEXTVAL伪列相同,引用格式为:序列名.currval。
序列还可应用于SELECT语句的其他形式。例如,在下面的SELECT语句中,序列seq1为每行数据提供了一个编号:
SELECT seq1.nextval, deptno, dname, loc FROM dept;
这条语句的执行结果类似于以下形式(这里假定第一次使用序列seq1):
NEXTVAL DEPTNO DNAME LOC
1 10 ACCOUNTING NEW YORK
2 20 RESEARCH DALLAS
3 30 SALES CHICAGO
在更多情况下序列的作用为表中的主键列或其他列提供一个唯一的序号。例如,要往表emp中插入一行时,可以利用序列为每个员工指定唯一的员工号。下面的INSERT语句向表emp中插入一行,其中empno的值为序列seq1中的下一个序号:
SQL>INSERT INTO emp(empno, ename, mgr, hiredate, deptno)
VALUES(seq1.nextval,'GOOD',7902,sysdate,20);
序列是一种共享式的数据库对象,用户可以直接使用自己创建的序列,其他用户也可以访问当前用户的序列,只要具有对这个序列的SELECT权限即可。如果一个序号被某个用户获得,那么其他用户就不能再获得这个序号了。也就是说,序列是可以共享的,但序列中的序号却是不能共享的。
对序列中序号的访问操作是作为一个单独的事务实现的,这个事务的执行与其他事务的执行成功与否无关。如果包含一条DML语句的事务被回滚了,那么对序列的操作是无法回滚的。假设序列seq1的当前序号是10,考虑下面的语句:
SQL>INSERT INTO dept VALUES(seq1.nextval,'NETWORK','BEIJING');
SQL>ROLLBACK;
SQL>SELECT seq1.nextval FROM dual;
如果上面的语句都执行成功,最后一条语句的执行结果是12。这是为什么呢?因为INSERT语句获得了序列seq1的下一个序号11,虽然这个事务被回滚了,但是序列中的指针还是向后移动了,序号11再也无法使用了,下一个可以使用的序号是12。
在访问序列中的序号时,可能会发生序号不连续的情况,不连续的原因可能是事务发生了回滚,或者多个用户共同访问同一个序列。
一个用户要访问其他用户的序列时,不仅要具有对这个序列的SELECT权限,在访问时还要在序列的名称前以用户名进行限定。例如,下面的SELECT语句是当前用户访问用户scott的序列seq1的情况:
SELECT scott.seq1.nextval FROM dual;
如果要将一个序列的SELECT权限授予其他用户,相应的GRANT命令格式为:
GRANT SELECT ON序列名TO用户名;