数据库

位置:IT落伍者 >> 数据库 >> 浏览文章

详解Oracle数据库中DUAL表的使用


发布日期:2020年07月11日
 
详解Oracle数据库中DUAL表的使用

DUAL表的用途

Dual 是 Oracle中的一个实际存在的表任何用户均可读取常用在没有目标表的Select语句块中

查看当前连接用户

SQL> select user from dual;

USER

SYSTEM

查看当前日期时间

SQL> select sysdate from dual;

SYSDATE

SQL> select to_char(sysdateyyyymmdd hh:mi:ss) from dual;

TO_CHAR(SYSDATEYYYYMMDDHH

::

当作计算器用

SQL> select + from dual;

+

查看序列值

SQL> create sequence aaa increment by start with ;

SQL> select aaanextval from dual;

NEXTVAL

SQL> select aaacurrval from dual;

CURRVAL

关于DUAL表的测试与分析

DUAL就是个一行一列的表如果你往里执行insertdeletetruncate操作就会导致很多程序出问题结果也因sql*pluspl/sql dev等工具而异

查看DUAL是什么OBJECT

DUAL是属于SYS schema的一个表然后以PUBLIC SYNONYM的方式供其他数据库USER使用

SQL> select owner object_name object_type from dba_objects where object_name like %DUAL%;

OWNER OBJECT_NAME OBJECT_TYPE

SYS DUAL TABLE

PUBLIC DUAL SYNONYM

查看表结构只有一个字段DUMMY为VARCHAR()型

SQL> desc dual

Name Type Nullable Default Comments

DUMMY VARCHAR() Y

DUAL表的结构

create table SYSDUAL

(

DUMMY VARCHAR()

)

tablespace SYSTEM

pctfree

pctused

initrans

maxtrans

storage

(

initial K

next K

minextents

maxextents

pctincrease

);

/*

很是困惑ORACLE为什么要用VARCHAR()型用CHAR()难道不好么?从这样的表结构来看DUAL表设计的目的就是要尽可能的简单以减少检索的开销

还有DUAL表是建立在SYSTEM表空间的第一是因为DUAL表是SYS这个用户建的本来默认的表空间就是SYSTEM第二把这个可能经常被查询的表和用户表分开来存放对于系统性能的是有好处的

有了创建了表创建了同义词还是不够的DUAL在SYS这个Schema下面因此用别的用户登录是无法查询这个表的因此还需要授权

grant select on SYSDUAL to PUBLIC with grant option;

将Select 权限授予公众接下来看看DUAL表中的数据事实上DUAL表中的数据和ORACLE数据库环境有着十分重要的关系(ORACLE不会为此瘫痪但是不少存储过程以及一些查询将无法被正确执行)

*/

查询行数

在创建数据库之后DUAL表中便已经被插入了一条记录个人认为DUMMY字段的值并没有什么关系重要的是DUAL表中的记录数

SQL> select count(*) from dual;

COUNT(*)

SQL> select * from dual;

DUMMY

X

插入数据再查询记录只返回一行记录

SQL> insert into dual values (Y);

row created

SQL> commit;

Commit complete

SQL> insert into dual values (X);

row created

SQL> insert into dual values (Z);

row created

SQL> commit;

Commit complete

SQL> select count(*) from dual;

COUNT(*)

SQL> select * from dual;

DUMMY

X

/*

假我们插入一条数据DUAL表不是返回一行而是多行记录那会是什么结果呢?

SQL> insert into dual values(Y);

行 已插入

SQL> commit;

提交完成

SQL> select * from dual;

DUMMY

X

Y

SQL> select sysdate from dual;

SYSDATE

这个时候返回的是两条记录这样同样会引起问题在通过使用

select sysdate into v_sysdate from dual;

来获取时间或者其他信息的存储过程来说ORACLE会抛出TOO_MANY_ROWS(ORA)异常

因此需要保证在DUAL表内有且仅有一条记录当然也不能把DUAL表的UPDATEINSERTDELETE权限随意释放出去这样对于系统是很危险的

*/

把表截掉

SQL> truncate table dual;

Table truncated

SQL> select count(*) from dual;

COUNT(*)

SQL> select * from dual;

no rows selected

SQL> select sysdate from dual;

no rows selected

试着把DUAL表中的数据删除看看会出现什么结果

SQL> delete from dual;

行 已删除

SQL> select * from dual;

DUMMY

SQL> select sysdate from dual;

SYSDATE

/*

我们便取不到系统日期了因为sysdate是个函数作用于每一个数据行现在没有数据了自然就不可能取出系统日期这个对于很多用

select sysdate into v_sysdate from dual;

这种方式取系统时间以及其他信息的存储过程来说是致命的因为Oracle会马上抛出一个NO_DATA_FOUND(ORA)的异常即使异常被捕获存储过程也将无法正确完成要求的动作

*/

对于DELETE操作来说ORACLE对DUAL表的操作做了一些内部处理尽量保证DUAL表中只返回一条记录当然这写内部操作是不可见的

不管表内有多少记录(没有记录除外)ORACLE对于每次DELETE操作都只删除了一条数据

SQL> select count(*) from dual;

COUNT(*)

SQL> delete from dual;

行 已删除

SQL> commit;

提交完成

SQL> select count(*) from dual;

COUNT(*)

/*

附: ORACLE关于DUAL表不同寻常特性的解释

There is internalized code that makes this happen Code checks that ensurethat a table scan of SYSDUAL only returns one row Svrmgrl behaviour is incorrect but this is now an obsolete product

The base issue you should always remember and keep is: DUAL table should always have ROW Dual is a normal table with one dummy column of varchar()

This is basically used from several applications as a pseudo table for getting results from a select statement that use functions like sysdate or other

prebuilt or application functions If DUAL has no rows at all some applications (that use DUAL) may fail with NO_DATA_FOUND exception If DUAL has more than row then applications (that use DUAL) may fail with TOO_MANY_ROWS exception

So DUAL should ALWAYS have and only row

*/

DUAL表可以执行插入更新删除操作还可以执行drop操作但是不要去执行drop表的操作否则会使系统不能用数据库起不了会报Database startup crashes with ORA错误

如果DUAL表被不幸删除后的恢复用sys用户登陆创建DUAL表授予公众SELECT权限(SQL如上述但不要给UPDATEINSERTDELETE权限)

向DUAL表插入一条记录(仅此一条) insert into dual values(X);提交修改

用sys用户登陆

SQL> create pfile=d:\pfilebak from spfile

SQL> shutdown immediate

在d:\pfilebak文件中最后加入一条replication_dependency_tracking = FALSE

重新启动数据库

SQL> startup pfile=d:\pfilebak

SQL> create table sysDUAL

( DUMMY varchar() )

pctfree pctused ;

SQL> insert into dual values(X);

SQL> commit;

SQL> Grant select on dual to Public;

授权成功

SQL> select * from dual;

D

X

SQL> shutdown immediate

数据库已经关闭

已经卸载数据库

ORACLE 例程已经关闭

SQL> startup

ORACLE 例程已经启动

Total System Global Area bytes

Fixed Size bytes

Variable Size bytes

Database Buffers bytes

Redo Buffers bytes

数据库装载完毕

数据库已经打开

SQL>

OK 下面就可以正常使用了

上一篇:VFP中调用Oracle的存储过程

下一篇:忘却Oracle的5个方面