oracle中的dual表
[font=微软雅黑, 宋体]DUAL表的用途
[font=微软雅黑, 宋体]Dual 是 Oracle中的一个实际存在的表,任何用户均可读取,常用在没有目标表的Select语句块中
[font=微软雅黑, 宋体]--查看当前连接用户
[font=微软雅黑, 宋体]SQL> select user from dual;
[font=微软雅黑, 宋体]USER
[font=微软雅黑, 宋体]--------
[font=微软雅黑, 宋体]SYSTEM
[font=微软雅黑, 宋体]--查看当前日期、时间
[font=微软雅黑, 宋体]sql> select sysdate from dual;
[font=微软雅黑, 宋体]SYSDATE
[font=微软雅黑, 宋体]---------
[font=微软雅黑, 宋体]2012-5-22
[font=微软雅黑, 宋体]sql> select to_char(sysdate,''yyyy-mm-dd hh24:mi:ss'') from dual;
[font=微软雅黑, 宋体]TO_CHAR(SYSDATE,''YYYY-MM-DDHH2
[font=微软雅黑, 宋体]------------------------------
[font=微软雅黑, 宋体]2007-01-24 15:02:47
[font=微软雅黑, 宋体]--当作计算器用
[font=微软雅黑, 宋体]SQL> select 1+2 from dual;
[font=微软雅黑, 宋体]1+2
[font=微软雅黑, 宋体]----------
[font=微软雅黑, 宋体]3
[font=微软雅黑, 宋体]--查看序列值
[font=微软雅黑, 宋体]SQL> create sequence aaa increment by 1 start with 1;
[font=微软雅黑, 宋体]SQL> select aaa.nextval from dual;
[font=微软雅黑, 宋体]NEXTVAL
[font=微软雅黑, 宋体]----------
[font=微软雅黑, 宋体]1
[font=微软雅黑, 宋体]SQL> select aaa.currval from dual;
[font=微软雅黑, 宋体]CURRVAL
[font=微软雅黑, 宋体]----------
[font=微软雅黑, 宋体]1
[font=微软雅黑, 宋体]=======================================================================
[font=微软雅黑, 宋体]关于DUAL表的测试与分析
[font=微软雅黑, 宋体] DUAL就是个一行一列的表,如果你往里执行insert、delete、truncate 操作,
[font=微软雅黑, 宋体]就会导致很多程序出问题。结果也因sql*plus、pl/sql dev等工具而异。
[font=微软雅黑, 宋体]=======================================================================
[font=微软雅黑, 宋体]查看DUAL是什么OBJECT
[font=微软雅黑, 宋体]DUAL是属于SYS schema的一个表, 然后以PUBLIC SYNONYM的方式供其他数据库USER使用
[font=微软雅黑, 宋体]SQL> select owner, object_name , object_type from dba_objects where object_name like '%DUAL%';
[font=微软雅黑, 宋体]OWNER OBJECT_NAME OBJECT_TYPE
[font=微软雅黑, 宋体]---- ------------ ------------------
[font=微软雅黑, 宋体]SYS DUAL TABLE
[font=微软雅黑, 宋体]PUBLIC DUAL SYNONYM
[font=微软雅黑, 宋体]--查看表结构,只有一个字段DUMMY,为VARCHAR2(1)型
[font=微软雅黑, 宋体]SQL> desc dual
[font=微软雅黑, 宋体]Name Type Nullable Default Comments
[font=微软雅黑, 宋体]----- ----------- -------- ------- --------
[font=微软雅黑, 宋体]DUMMY VARCHAR2(1) Y
[font=微软雅黑, 宋体]--DUAL表的结构:
[font=微软雅黑, 宋体]CREATE TABLE "SYS"."DUAL"
[font=微软雅黑, 宋体](
[font=微软雅黑, 宋体]"DUMMY" VARCHAR2(1)
[font=微软雅黑, 宋体])
[font=微软雅黑, 宋体]PCTFREE 10
[font=微软雅黑, 宋体]PCTUSED 40
[font=微软雅黑, 宋体]INITRANS 1
[font=微软雅黑, 宋体]MAXTRANS 255
[font=微软雅黑, 宋体]NOCOMPRESS LOGGING
[font=微软雅黑, 宋体]STORAGE(
[font=微软雅黑, 宋体] INITIAL 16384
[font=微软雅黑, 宋体] NEXT 1048576
[font=微软雅黑, 宋体] MINEXTENTS 1
[font=微软雅黑, 宋体] MAXEXTENTS 2147483645
[font=微软雅黑, 宋体] PCTINCREASE 0
[font=微软雅黑, 宋体] FREELISTS 1
[font=微软雅黑, 宋体] FREELIST GROUPS 1
[font=微软雅黑, 宋体] BUFFER_POOL DEFAULT)
[font=微软雅黑, 宋体]TABLESPACE "SYSTEM"
[font=微软雅黑, 宋体] DUAL表是建立在SYSTEM表空间的,第一是因为DUAL表是SYS这个用
[font=微软雅黑, 宋体]户建的,本来默认的表空间就是SYSTEM;第二,把这个可能经常被查询的表
[font=微软雅黑, 宋体]和用户表分开来存放,对于系统性能的是有好处的。
[font=微软雅黑, 宋体] 有了创建了表、创建了同义词还是不够的。DUAL在SYS这个Schema下面,
[font=微软雅黑, 宋体]因此用别的用户登录是无法查询这个表的,因此还需要授权:
[font=微软雅黑, 宋体] grant select on SYS.DUAL to PUBLIC with grant option;
[font=微软雅黑, 宋体] 将Select 权限授予公众。
[font=微软雅黑, 宋体] 事实上,DUAL表中的数据和ORACLE数据库环境有着十分重要的关系(ORACLE不会为此瘫痪,但是不少存储过程以
[font=微软雅黑, 宋体]及一些查询将无法被正确执行)。
[font=微软雅黑, 宋体]=======================================================================
[font=微软雅黑, 宋体]DUAL 表行数问题
[font=微软雅黑, 宋体]SQL> select count(*) from dual;
[font=微软雅黑, 宋体]COUNT(*)
[font=微软雅黑, 宋体]----------
[font=微软雅黑, 宋体]1
[font=微软雅黑, 宋体]SQL> select * from dual;
[font=微软雅黑, 宋体]DUMMY
[font=微软雅黑, 宋体]-----
[font=微软雅黑, 宋体]X
[font=微软雅黑, 宋体]--插入数据,再查询记录,只返回一行记
[font=微软雅黑, 宋体]SQL> insert into dual values ('Y');
[font=微软雅黑, 宋体]1 row created.
[font=微软雅黑, 宋体]SQL> commit;
[font=微软雅黑, 宋体]Commit complete.
[font=微软雅黑, 宋体]SQL> insert into dual values ('X');
[font=微软雅黑, 宋体]1 row created.
[font=微软雅黑, 宋体]SQL> insert into dual values ('Z');
[font=微软雅黑, 宋体]1 row created.
[font=微软雅黑, 宋体]SQL> commit;
[font=微软雅黑, 宋体]Commit complete.
[font=微软雅黑, 宋体]SQL> select count(*) from dual;
[font=微软雅黑, 宋体]COUNT(*)
[font=微软雅黑, 宋体]----------
[font=微软雅黑, 宋体]4
[font=微软雅黑, 宋体]SQL> select * from dual;
[font=微软雅黑, 宋体]DUMMY
[font=微软雅黑, 宋体]-----
[font=微软雅黑, 宋体]X --这里查就剩下一行数据了
[font=微软雅黑, 宋体]----------------------------------------------------------------------------
[font=微软雅黑, 宋体]SQL> insert into dual values(''Y'');
[font=微软雅黑, 宋体]1 行 已插入
[font=微软雅黑, 宋体]SQL> commit;
[font=微软雅黑, 宋体]提交完成
[font=微软雅黑, 宋体]SQL> select * from dual;
[font=微软雅黑, 宋体]DUMMY
[font=微软雅黑, 宋体]-----
[font=微软雅黑, 宋体]X
[font=微软雅黑, 宋体]Y
[font=微软雅黑, 宋体]SQL> select sysdate from dual;
[font=微软雅黑, 宋体]SYSDATE
[font=微软雅黑, 宋体]-----------
[font=微软雅黑, 宋体]2012-5-22
[font=微软雅黑, 宋体]2012-5-22
[font=微软雅黑, 宋体]这个时候返回的是两条记录,这样同样会引起问题。在通过使用
[font=微软雅黑, 宋体]SQL>select sysdate into v_sysdate from dual;
[font=微软雅黑, 宋体]来获取时间或者其他信息的存储过程来说 ,ORACLE 会抛出TOO_MANY_ROWS(ORA-01422)异常。
[font=微软雅黑, 宋体]----------------------------------------------------------------------------
[font=微软雅黑, 宋体]--把表截掉
[font=微软雅黑, 宋体]SQL> truncate table dual;
[font=微软雅黑, 宋体]Table truncated.
[font=微软雅黑, 宋体]SQL> select count(*) from dual;
[font=微软雅黑, 宋体]COUNT(*)
[font=微软雅黑, 宋体]----------
[font=微软雅黑, 宋体]0
[font=微软雅黑, 宋体]SQL> select * from dual;
[font=微软雅黑, 宋体]no rows selected
[font=微软雅黑, 宋体]SQL> select sysdate from dual;
[font=微软雅黑, 宋体]no rows selected
[font=微软雅黑, 宋体]--试着把DUAL表中的数据删除,看看会出现什么结果:
[font=微软雅黑, 宋体]SQL> delete from dual;
[font=微软雅黑, 宋体]1 行 已删除
[font=微软雅黑, 宋体]SQL> select * from dual;
[font=微软雅黑, 宋体]DUMMY
[font=微软雅黑, 宋体]-----
[font=微软雅黑, 宋体]SQL> select sysdate from dual;
[font=微软雅黑, 宋体]SYSDATE
[font=微软雅黑, 宋体]-----------
[font=微软雅黑, 宋体] 我们便取不到系统日期了。因为,sysdate是个函数,作用于每一个数据行。现在没有数据了,自然就不可能取出系统日期。
[font=微软雅黑, 宋体] 这个对于很多用:
[font=微软雅黑, 宋体]SQL>select sysdate into v_sysdate from dual;
[font=微软雅黑, 宋体] 这种方式取系统时间以及其他信息的存储过程来说是致命的,因为,
[font=微软雅黑, 宋体]ORACLE会马上抛出一个NO_DATA_FOUND(ORA-01403)的异常,即使异常
[font=微软雅黑, 宋体]被捕获,存储过程也将无法正确完成要求的动作。
[font=微软雅黑, 宋体]----------------------------------------------------------------------------
[font=微软雅黑, 宋体] 对于delete操作来说,oracle对dual表的操作做了一些内部处理,尽量保证dual表中只返回一条记录,
[font=微软雅黑, 宋体]当然这些内部操作是不可见的
[font=微软雅黑, 宋体] 不管表内有多少记录(没有记录除外),oracle对于每次delete操作都只删除一条数据。
[font=微软雅黑, 宋体]SQL> select count(*) from dual;
[font=微软雅黑, 宋体]COUNT(*)
[font=微软雅黑, 宋体]----------
[font=微软雅黑, 宋体]2
[font=微软雅黑, 宋体]SQL> delete from dual;
[font=微软雅黑, 宋体]1 行 已删除
[font=微软雅黑, 宋体]SQL> commit;
[font=微软雅黑, 宋体]提交完成
[font=微软雅黑, 宋体]SQL> select count(*) from dual;
[font=微软雅黑, 宋体]COUNT(*)
[font=微软雅黑, 宋体]----------
[font=微软雅黑, 宋体]1
[font=微软雅黑, 宋体]=======================================================================
[font=微软雅黑, 宋体]Drop Dual table
[font=微软雅黑, 宋体] DUAL表可以执行插入、更新、删除操作,还可以执行drop操作。但是不要去执行drop表的操作,否则会使系统
[font=微软雅黑, 宋体]不能用,数据库起不了,会报Databasestartup crashes with ORA-1092错误。
[font=微软雅黑, 宋体]DUAL表被"不幸"删除后的恢复:
[font=微软雅黑, 宋体](1)用sys用户登陆。
[font=微软雅黑, 宋体]SQL> create pfile=‘d:\pfile.bak‘ from spfile
[font=微软雅黑, 宋体]SQL> shutdown immediate
[font=微软雅黑, 宋体](2)创建DUAL表。
[font=微软雅黑, 宋体] CREATE TABLE "SYS"."DUAL"
[font=微软雅黑, 宋体](
[font=微软雅黑, 宋体]"DUMMY" VARCHAR2(1)
[font=微软雅黑, 宋体])
[font=微软雅黑, 宋体]PCTFREE 10
[font=微软雅黑, 宋体]PCTUSED 40
[font=微软雅黑, 宋体]INITRANS 1
[font=微软雅黑, 宋体]MAXTRANS 255
[font=微软雅黑, 宋体]NOCOMPRESS LOGGING
[font=微软雅黑, 宋体]STORAGE(
[font=微软雅黑, 宋体] INITIAL 16384
[font=微软雅黑, 宋体] NEXT 1048576
[font=微软雅黑, 宋体] MINEXTENTS 1
[font=微软雅黑, 宋体] MAXEXTENTS 2147483645
[font=微软雅黑, 宋体] PCTINCREASE 0
[font=微软雅黑, 宋体] FREELISTS 1
[font=微软雅黑, 宋体] FREELIST GROUPS 1
[font=微软雅黑, 宋体] BUFFER_POOL DEFAULT)
[font=微软雅黑, 宋体]TABLESPACE "SYSTEM" ;
[font=微软雅黑, 宋体](3)授予公众SELECT权限(SQL如下,但不要给UPDATE,INSERT,DELETE权限)
[font=微软雅黑, 宋体]sql> grant select on dual to Public;
[font=微软雅黑, 宋体]sql> select * from dual;
[font=微软雅黑, 宋体](4)向DUAL表插入一条记录(仅此一条): insert into dual values('X');
[font=微软雅黑, 宋体]sql> insert into dual values(?X‘);
[font=微软雅黑, 宋体](5)提交修改。
[font=微软雅黑, 宋体]sql> commit;
[font=微软雅黑, 宋体]最后:
[font=微软雅黑, 宋体]SQL> shutdown immediate
[font=微软雅黑, 宋体]SQL> startup
[font=微软雅黑, 宋体]--OK, 下面就可以正常使用了。