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> 

回答:


29

ウィキペディアから:

DUALテーブルは、すべてのOracleデータベースインストールでデフォルトで存在する特別な1行のテーブルです。SYSDATEやUSERなどの疑似列の選択での使用に適しています。表には、値が「X」であるDUMMYと呼ばれる単一のVARCHAR2(1)列があります。

したがって、二重テーブルは、空ではなく空のテーブルであるものに対して操作を実行する方法です。これは、テーブルを気にしないが、selectステートメントを介して操作を実行する必要がある場合に便利です。テーブルに複数の行または列がある場合、複数の結果が返されます(操作を実行するときにタプルのセット全体を操作するため)。

特にSQLを介して特定のプロシージャを呼び出す必要がない限り、本番環境では使用しないでください。

4*5'Foo' 文字列と同様に、数学的な操作です。したがって、すべてのテーブルから「4 * 5」を選択できるように、「Foo」を任意のテーブルから選択できるように、DUALは複数の結果を持たない既知の良好なテーブルから選択する方法です。

ドキュメントから(概念):

DUALは、Oracle Databaseおよびユーザー作成プログラムが参照して既知の結果を保証できるデータ・ディクショナリ内の小さな表です。デュアルテーブルは、現在の日時など、値を1回だけ返す必要がある場合に便利です。すべてのデータベースユーザーはDUALにアクセスできます。

DUALテーブルには、DUMMYと呼ばれる1つの列と、値Xを含む1つの行があります。

そしてSQLリファレンス

DUALは、データディクショナリとともにOracleデータベースによって自動的に作成されるテーブルです。DUALはユーザーSYSのスキーマにありますが、すべてのユーザーがDUALという名前でアクセスできます。VARCHAR2(1)と定義された1つの列DUMMYがあり、値Xを持つ1つの行が含まれています。DUALテーブルから選択すると、SELECTステートメントで定数式を計算するのに役立ちます。DUALには行が1つしかないため、定数は1回だけ返されます。または、任意のテーブルから定数、擬似列、または式を選択できますが、値はテーブル内の行の数だけ返されます。DUALから定数値を選択する多くの例については、「SQL関数について」を参照してください。

Oracle Database 10gリリース1以降、DUMMY列を含まない式を計算する場合、DUAL表で論理I / Oは実行されません。この最適化は、実行計画でFAST DUALとしてリストされます。DUALからDUMMY列を選択すると、この最適化は行われず、論理I / Oが発生します。


5
「SQLを介して特定のプロシージャを呼び出す必要がない限り、本番環境では使用しないでください」
ニックピアポイント

2
また、本番環境で使用すべきでないことに同意できません。それは私にとって「ローストの端を切る」ミームのように聞こえます。
-ErikE

1
この答えはそれ自体に同意しないため、改善が必要です。:公式ドキュメントから、それはコピー一つの場所に「デュアルテーブルが便利ですと別で、それは推奨しています「これは使用すべきではない生産で、しない限り...」
ypercubeᵀᴹ

18

DUAL 次のSQLステートメントが示すように、正確に1行のテーブルです。

SELECT * FROM dual;

あなたのdual2テーブルには行がありません。挿入すると、同じ動作が見られます。

4 * 5は、テーブルのデータを実際に使用せずにOracleが評価できる式です。通常の列式で行うのと同じように、行ごとに1回評価します。したがって、行がない場合、結果は返されません。2行ある場合、20を2回取得します。


14

このdualテーブルは、他のテーブルの動作とほぼ同じように「機能」します。これは、レコードを選択できるテーブルです。

これは、たとえば、テーブルを説明できることを意味します。ここにありますSQL*Plus

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

だから、テーブルには、名前の1列、持ってdummyいますvarchar2(1)

設計上、テーブルには1つのレコードがあります(少なくとも誰もいじっていない場合)。

SQL> select count(*) from dual;

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

だから、同じ動作を得るために、dual2あなたが持っているようにdual、あなたはデュアルに1つのレコードを挿入する必要があります。さらに良いことに、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は、インスタンスは開始されているがデータベースが開かれていないときに機能する数少ない「テーブル」の1つです。

あなたは次のようなものを得ます

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

9

他の回答に加えて、OracleはスペースSQLテキストについてあまり気にしません(少なくともいくつかの場所では)。SQLパーサーは、空白だけでなく、文字クラスの違いによってもトークン化します。

たとえば、次のステートメントを実行できます。

SQL> select * from dual;

D
-
バツ


SQL> select(1)from dual;

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

SQL> select-null from dual;

     -ヌル
----------


SQL> select-1 from dual;

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

SQL> 

空白を入れずにSQLを実行することもできます。

SQL> select * from / ** / dual;

D
-
バツ

ここにいくつかの例があります:

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

タネル・ポーダー


2
多くのスペースを省略するこの機能は、Oracleに固有のものではありません。SQL Serverでも同じように機能します。
エリク


4

質問は既に回答済みです。これらは、デュアルテーブルの目的に関する注意事項です。dualは、select句の式を評価するために使用できます。他の多くのデータベースシステムでは、この目的のためにこのようなテーブルは必要ありません。MS SQL Server、MySql、Posgresは次のステートメントを評価できます

select 3+5 ;

オラクルはできません。Oracleのselect文には、常に「from」句が必要です。

DUMPのような一部の関数はpl / sql式で使用できません。

そう

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のメモリ構造にもあるように見えます。2つのEXPLAIN PLANの違いに注意してください。MySQLのDUALでは「テーブルは使用されません」。

興味深いことに、MySQLのデュアルではDESCを実行できません。これはOracleとは異なりますが、Oracle構文がMySQLで動作できるようにするために特にAIUIが導入されました。

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データベースでは、基本的に、デュアルテーブルを使用して擬似列の値を取得します。次のプロパティが含まれます。

  1. sysユーザーが所有しています
  2. すべてのユーザーが利用できます
  3. 名前がデータ型Varchar2(1)のダミーである1つの列のみが含まれます。この列には最大1文字の幅を指定できます。

詳細を知りたい場合は、こちらをチェックしてください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.