ตาราง 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 ทั้งหมด เหมาะสำหรับใช้ในการเลือกนามแฝงเช่น SYSDATE หรือ USER ตารางมีคอลัมน์ VARCHAR2 (1) เดียวที่เรียกว่า DUMMY ที่มีค่า 'X'

ดังนั้นตารางคู่เป็นวิธีการดำเนินการกับจำนวนเงินที่จะเป็นตารางที่ว่างเปล่า แต่ไม่ว่าง สิ่งนี้มีประโยชน์เมื่อไม่มีใครสนใจตาราง แต่ต้องดำเนินการผ่านคำสั่ง select หากตารางมีมากกว่าหนึ่งแถวหรือคอลัมน์ผลลัพธ์หลายรายการจะถูกส่งคืน (เนื่องจากการดำเนินการกับทั้งชุดของ tuples เมื่อทำการดำเนินการ)

ไม่ควรใช้ในการผลิตเว้นแต่คุณจะต้องเรียกใช้ขั้นตอนบางอย่างผ่านทาง SQL โดยเฉพาะ

4*5เป็นการดำเนินการทางคณิตศาสตร์เช่นเดียว'Foo' กับสตริง ดังนั้นเช่นเดียวกับที่สามารถเลือก 4 * 5 จากตารางใดก็ได้เช่นเดียวกับที่สามารถเลือก 'Foo' จากตารางใด ๆ DUAL เป็นวิธีการเลือกจากตารางที่รู้จักดีซึ่งจะไม่มีผลลัพธ์หลายรายการ

จากเอกสาร (แนวคิด):

DUAL เป็นตารางเล็ก ๆ ในพจนานุกรมข้อมูลที่ Oracle Database และโปรแกรมที่ผู้ใช้เขียนสามารถอ้างอิงเพื่อรับประกันผลลัพธ์ที่ทราบ ตารางคู่มีประโยชน์เมื่อต้องส่งคืนค่าเพียงครั้งเดียวเช่นวันที่และเวลาปัจจุบัน ผู้ใช้ฐานข้อมูลทั้งหมดสามารถเข้าถึง DUAL

ตาราง DUAL มีหนึ่งคอลัมน์ที่เรียกว่า DUMMY และหนึ่งแถวที่มีค่า X

และการอ้างอิง SQL :

DUAL เป็นตารางที่สร้างขึ้นโดยอัตโนมัติโดย Oracle Database พร้อมกับ data dictionary DUAL อยู่ในสคีมาของผู้ใช้ SYS แต่สามารถเข้าถึงได้โดยชื่อ DUAL สำหรับผู้ใช้ทั้งหมด มันมีหนึ่งคอลัมน์ DUMMY ซึ่งถูกกำหนดให้เป็น VARCHAR2 (1) และมีหนึ่งแถวที่มีค่า X การเลือกจากตาราง DUAL มีประโยชน์สำหรับการคำนวณนิพจน์คงที่ด้วยคำสั่ง SELECT เนื่องจาก DUAL มีเพียงหนึ่งแถวค่าคงที่จึงถูกส่งคืนเพียงครั้งเดียว หรือคุณสามารถเลือกค่าคงที่ pseudocolumn หรือนิพจน์จากตารางใดก็ได้ แต่ค่าจะถูกส่งกลับหลายครั้งตามที่มีแถวในตาราง อ้างอิงถึง "เกี่ยวกับฟังก์ชัน SQL" สำหรับตัวอย่างมากมายในการเลือกค่าคงที่จาก DUAL

เริ่มต้นด้วย Oracle Database 10g รีลีส 1 ลอจิคัล I / O ไม่ได้ถูกดำเนินการบนตาราง DUAL เมื่อคำนวณนิพจน์ที่ไม่รวมคอลัมน์ DUMMY การปรับให้เหมาะสมนี้แสดงเป็น FAST DUAL ในแผนการดำเนินการ หากคุณเลือกคอลัมน์ DUMMY จาก DUAL การเพิ่มประสิทธิภาพนี้จะไม่เกิดขึ้นและ I / O เชิงตรรกะจะเกิดขึ้น


5
"ไม่ควรใช้ในการผลิตเว้นแต่คุณจะต้องเรียกใช้ขั้นตอนบางอย่างผ่าน SQL โดยเฉพาะ" เพราะเหตุใด
Nick Pierpoint

2
ฉันไม่สามารถตกลงกันได้ว่าไม่ควรใช้ในการผลิต นั่นฟังดูเหมือน "ตัดปลายออกจากเนื้อย่าง" สำหรับฉัน
ErikE

1
คำตอบนี้ต้องการการปรับปรุงตามที่เห็นด้วยกับตัวเอง ในที่เดียวมันคัดลอกมาจากเอกสารอย่างเป็นทางการ: "ตารางคู่มีประโยชน์ "และในอีกกรณีหนึ่งแนะนำว่า " ไม่ควรใช้ในการผลิตเว้นแต่จะเป็น ... "
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)

ดังนั้นตารางมีคอลัมน์หนึ่งชื่อซึ่งเป็นdummyvarchar2(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

ก่อนหน้านี้ฉันพูดว่า dual เกือบใช้งานได้เหมือนโต๊ะอื่น ดังนั้นเมื่อมันไม่ทำงานเหมือนโต๊ะอื่น ๆ ?

มันทำงานแตกต่างกันหากไม่มีการเลือกค่าจากตาราง อีกครั้งด้วยคำสั่งของคุณฉันให้ 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 accessdual2

ตอนนี้สิ่งเดียวกันกับ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

นอกเหนือจากคำตอบอื่น ๆ แล้วออราเคิลยังไม่ค่อยเลือกสรรกับข้อความ SQL ช่องว่าง (อย่างน้อยก็ในบางที่) ตัวแยกวิเคราะห์ SQL ยังโทเค็นโดยความแตกต่างของคลาสอักขระในบางกรณีไม่ใช่แค่ช่องว่าง

ตัวอย่างเช่นคุณสามารถเรียกใช้คำสั่งดังกล่าว:

SQL เลือก * จาก dual;

D
-
X


SQL เลือก (1) จาก dual;

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

SQL> select-null จาก dual;

     -NULL
----------


SQL เลือก 1 จากคู่;

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

SQL> 

นอกจากนี้ยังเป็นไปได้ที่จะเรียกใช้ SQL โดยไม่มีช่องว่างใด ๆ

SQL เลือก * จาก / ** / dual;

D
-
X

ฉันมีตัวอย่างเพิ่มเติมที่นี่:

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

Tanel Poder


2
ความสามารถในการเว้นช่องว่างจำนวนมากนี้ไม่ได้เป็นเอกลักษณ์ของ Oracle ทำงานเหมือนกันใน SQL Server
ErikE

8

การดำเนินการสองอย่างรวดเร็วเขียนรหัสของคุณใหม่เพื่อสอบถาม x $ dual เนื่องจาก "table" นี้เป็นโครงสร้างข้อมูล C ใน SGA คุณสามารถค้นหาได้ในโหมดการต่อรอง


4

คำถามได้รับคำตอบแล้ว นี่คือบันทึกย่อบางส่วนตามวัตถุประสงค์ของตารางคู่ Dual สามารถใช้ในการประเมินค่านิพจน์ในส่วนคำสั่งที่เลือก ระบบฐานข้อมูลอื่น ๆ จำนวนมากไม่ต้องการตารางดังกล่าวเพื่อจุดประสงค์นี้ MS SQL Server, MySql, Posgres สามารถประเมินข้อความต่อไปนี้

select 3+5 ;

ออราเคิลไม่สามารถ คำสั่ง select ของ Oracle ต้องการคำสั่ง "from" --clause เสมอ

ฟังก์ชั่นบางอย่างไม่สามารถนำมาใช้ใน 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 เช่นกัน สังเกตเห็นความแตกต่างในทั้งสองอธิบายแผน - "ไม่มีตารางที่ใช้" สำหรับ DUAL ใน MySQL

อย่างไรก็ตามที่น่าสนใจฉันไม่สามารถทำ DESC บนคู่ของ MySQL ซึ่งแตกต่างจาก 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 table ถูกใช้เพื่อรับค่าของคอลัมน์หลอก มันมีคุณสมบัติดังต่อไปนี้:

  1. มันเป็นเจ้าของโดยผู้ใช้ sys
  2. มันสามารถใช้ได้สำหรับผู้ใช้ทั้งหมด
  3. มันมีเพียงหนึ่งคอลัมน์ซึ่งชื่อเป็นหุ่นที่มีประเภทข้อมูล Varchar2 (1) คอลัมน์นี้สามารถมีความกว้างสูงสุดของตัวละครตัวหนึ่ง

หากคุณต้องการรายละเอียดเพิ่มเติมตรวจสอบที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.