Oracle DUAL表如何工作?


32
SQL> desc dual
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 DUMMY                                              VARCHAR2(1)

SQL> select 4*5 from dual;

       4*5
----------
        20

SQL>

我觉得这很奇怪。如果双对中没有名为4 * 5的列,那么select语句如何工作?

另外,为什么在创建自己的双表时看不到相同的行为?

SQL> create table dual2(dummy varchar2(1)); 

Table created.

SQL> desc dual2
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 DUMMY                                              VARCHAR2(1)

SQL> select 4*5 from dual2;

no rows selected

SQL> 

Answers:


29

维基百科

DUAL表是一种特殊的单行表,默认情况下在所有Oracle数据库安装中都存在。它适用于选择伪列,例如SYSDATE或USER。该表具有一个名为DUMMY的VARCHAR2(1)列,其值为'X'。

因此,对偶表是一种针对空表而不是空表执行操作的方法。当人们不关心表但需要通过select语句执行操作时,这很有用。如果表具有多于一行或一列,则将返回多个结果(由于在执行操作时对整个元组进行了操作)。

除非您特别需要通过SQL调用某些过程,否则不应在生产中使用它。

4*5 是数学运算,就像 'Foo' 字符串一样。因此,就像一个人可以从任何表中选择4 * 5一样,就像一个人可以从任何表中选择“ Foo”一样,DUAL是从永远不会有多个结果的已知有效表中选择它的一种方式。

文档(CONCEPTS):

DUAL是数据字典中的一个小表,Oracle数据库和用户编写的程序可以参考DUAL来保证已知结果。当必须仅返回一个值(例如,当前日期和时间)一次时,双重表很有用。所有数据库用户都可以访问DUAL。

DUAL表具有称为DUMMY的一列和包含值X的一行。

SQL参考

DUAL是由Oracle数据库自动创建的表以及数据字典。DUAL在用户SYS的架构中,但所有用户均可通过名称DUAL访问。它具有一列DUMMY,定义为VARCHAR2(1),并且包含一行带有值X的行。从DUAL表中进行选择对于使用SELECT语句计算常量表达式很有用。由于DUAL只有一行,因此该常数仅返回一次。或者,您可以从任何表中选择一个常量,伪列或表达式,但是该值将返回与该表中的行一样多的次数。有关从DUAL中选择常量值的许多示例,请参见“关于SQL函数”。

从Oracle数据库10g第1版开始,当计算不包含DUMMY列的表达式时,不对DUAL表执行逻辑I / O。该优化在执行计划中列为“快速双重”。如果从DUAL中选择DUMMY列,则不会进行此优化,并且会发生逻辑I / O。


5
“除非您特别需要通过SQL调用某些过程,否则不应在生产中使用它”为什么不呢?
尼克·皮尔波因特

2
我也不同意不应在生产中使用它。对我来说,这听起来像是“砍掉烤头”。
ErikE

1
该答案与自己不同,因此需要改进。在一个地方,它复制从官方文档:“DUAL表是有用的,而在另一个它建议“它不应该被用来在生产,除非......”
ypercubeᵀᴹ

18

DUAL 是一个表,其中只有一行,如以下SQL语句所示:

SELECT * FROM dual;

您的dual2表没有行。如果您插入一个,您将看到相同的行为。

4 * 5是Oracle可以评估的表达式,而无需实际使用表中的数据。它将对每行评估一次,就像对普通列表达式进行评估一样。因此,如果没有行,则不会返回任何结果,如果有两行,您将获得20次两次。


14

dual几乎可以像其他任何表一样工作:它是一个表,您可以从中选择记录。

例如,这意味着您可以描述表格。在这里SQL*Plus

SQL> set lines 50
SQL> desc dual
Name                    Null?    Typ
----------------------- -------- ----------------
DUMMY                            VARCHAR2(1)

所以,这个表有一列,命名dummy这是一个varchar2(1)

通过设计,该表具有一个记录(至少如果没有人摆弄它):

SQL> select count(*) from dual;

COUNT(*)
----------
         1

因此,为了得到与相同的行为dual2,你有dual,你必须插入一条记录成双。更好的是,使用create table as select(ctas)创建它:

SQL> create table dual2 as select * from dual;

现在,您的查询有效:

SQL> select 4*5 from dual2;
       4*5
----------
        20

之前,我说过对偶几乎与其他任何表一样工作。那么,什么时候它不能像其他任何表一样工作?

如果未从表本身中选择任何值,则其行为会有所不同。再次,根据您的查询,我让Oracle对其进行解释 ...

SQL> set lines 150
SQL> explain plan for select 4*5 from dual2;

EXPLAIN PLAN ausgef³hrt.

...以查看如何访问该表:

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 3445655939

-------------------------------------------------------------------
| Id  | Operation         | Name  | Rows  | Cost (%CPU)| Time     |
-------------------------------------------------------------------
|   0 | SELECT STATEMENT  |       |     1 |     3   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| DUAL2 |     1 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------

可以看出该语句执行full table accesson dual2

现在,与dual

SQL> explain plan for select 4*5 from dual;

EXPLAIN PLAN ausgef³hrt.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------
Plan hash value: 1388734953

-----------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Cost (%CPU)| Time     |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     1 |     2   (0)| 00:00:01 |
|   1 |  FAST DUAL       |      |     1 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------

这是dual表行为不同的地方:dummy不需要的值,因此将fast dual执行操作,以使实例不读取磁盘上的实际值。


10

顺便说一句,当实例启动但尚未打开数据库时,DUAL是少数工作的“表”之一。

你得到类似的东西

ADDR     INDX   INST_ID D
-------- ------ ------- -
0C0362D4      0       1 X

9

除了其他答案外,Oracle对于空格SQL文本(至少在某些地方)不是很挑剔。在某些情况下,SQL解析器还会通过字符类差异来标记,而不仅仅是空白。

例如,您可以运行以下语句:

SQL> select * from对偶;

d
--
X


SQL> select(1)从双;

       (1)
----------
         1个

SQL>从双选择空

     -空值
----------


SQL> select-1 from dual;

        -1
----------
        -1

SQL> 

也可以在其中没有任何空格的情况下运行SQL:

SQL> select * from / ** / dual;

d
--
X

我在这里还有更多示例:

http://blog.tanelpoder.com/2008/01/14/can-you-write-a-working-sql-statement-without-using-any-whitespace/

坦尼尔·波特


2
忽略许多空间的能力不是Oracle独有的。在SQL Server中的工作原理相同。
ErikE

8

快速的双重操作会重新编写您的代码以查询x $ dual。由于此“表”是SGA中的C数据结构,因此可以在nomount模式下查询它。


4

问题已经回答。这些是对双重表目的的一些说明。Dual可用于在select子句中计算表达式。为此,许多其他数据库系统不需要这样的表。MS SQL Server,MySql,Posgres可以评估以下语句

select 3+5 ;

Oracle不能。Oracle select语句始终需要一个“从”子句。

某些功能不能在pl / sql表达式中使用,例如DUMP

所以

declare
str varchar2(100);
begin
str:=dump('Hallo');
end;
/

会引发异常,但

declare
str varchar2(100);
begin
select dump('Hallo') into str from dual;
end;
/

将工作。

它可以用于扩展查询的结果集

select user_id,username from user_users
union all
select -1,'NO USER'
from dual
/

这给了

| USER_ID |     USERNAME |
|---------|--------------|
|  476267 | USER_4_E8C50 |
|      -1 |      NO USER |

或使用以下任一查询生成数据CONNECT BY

select level as n 
from dual
connect by level <= 5 ;

或递归CTE:

with nlist(n) as (
  select 1 from dual
  union all
  select n+1
  from nlist 
  where n<5    )
select n
from nlist
 ;

哪个返回

| N |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |

sqlfiddle中


3

就其价值而言,它在MySQL中的工作方式完全相同。

mysql> use test;
Database changed

mysql> create table fred(billy int);
Query OK, 0 rows affected (0.79 sec)

mysql> select 4 + 5 from fred;
Empty set (0.00 sec)

mysql> select 4 + 5 as mary from fred;
Empty set (0.00 sec)

mysql> insert into fred values(1);
Query OK, 1 row affected (0.13 sec)

mysql> select 4 + 5 from fred;
+-------+
| 4 + 5 |
+-------+
|     9 |
+-------+
1 row in set (0.00 sec)

mysql> select 4 + 5 as mary from fred;
+------+
| mary |
+------+
|    9 |
+------+
1 row in set (0.00 sec)

mysql> insert into fred values(2);
Query OK, 1 row affected (0.08 sec)

mysql> select 4 + 5 from fred;
+-------+
| 4 + 5 |
+-------+
|     9 |
|     9 |
+-------+
2 rows in set (0.00 sec)

mysql> select 4 + 5 as mary from fred;
+------+
| mary |
+------+
|    9 |
|    9 |
+------+
2 rows in set (0.00 sec)

mysql> explain select 4 + 5 as mary from fred;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | fred  | ALL  | NULL          | NULL | NULL    | NULL |    2 | NULL  |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)

mysql> 

而且看来DUAL也是MySQL中某种形式的内存结构。注意两个解释计划的区别-MySQL中DUAL的“未使用表”。

但是,有趣的是,我无法在MySQL的双重数据库上执行DESC,这与Oracle不同-但是它是专门为AIUI引入的,以允许Oracle语法在MySQL上运行。

mysql> select 4 + 5 from dual;
+-------+
| 4 + 5 |
+-------+
|     9 |
+-------+
1 row in set (0.00 sec)

mysql> explain select 4 + 5 from dual;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)

mysql> desc dual;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'dual' at line 1
mysql> 

2

在oracle数据库中,Dual表基本上用于获取伪列的值。它包含以下属性:

  1. 它归sys用户所有
  2. 适用于所有用户
  3. 它仅包含一列名称为虚拟的数据类型为Varchar2(1),此列的最大宽度为一个字符。

如果您想了解更多细节,请点击这里

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.