为什么必须从对偶表中进行选择?


15

这适用于最可能出现在StackOverflow / dba.stackexchange上的主要关系数据库管理系统,它们是SQL Server,MySQL,PostgreSQL和SQLite(WebSQL)

select 'abc' abc, 1 def;

它在Oracle上不起作用。为什么我们需要从Oracle的DUAL中进行选择?SQL的ISO / ANSI标准是否需要SELECT语句的FROM子句?


编辑:

根据Per Bacon Bit的回答,SQL标准似乎确实需要这样做。

因此,在现实中,因为DUAL名字是这样的用词不当,如果我要创建一个表,并将其命名为Atom或ONE,如create table one (atom int);.. select 'abc' abc, 1 def FROM one;-有没有比较的性能损失SELECT .. FROM DUAL


认为 DB2还不能做一个select没有from。DB2有一个类似的伪表,称为SYSIBM.SYSDUMMY1。您可能也已经知道这一点,但是当您使用时select 'A' from dualdual没有真正访问该表,它会在您的编辑中回答问题(顺便提一个新问题)。
杰克说请尝试topanswers.xyz 2012年

1
它并没有在“所有” DBMS工作。有几种DBMS在没有FROM的情况下不允许进行SELECT。:手动回答您的问题有关性能docs.oracle.com/cd/E11882_01/server.112/e26088/...
a_horse_with_no_name

3
@JackDouglas:你是正确的。DB2确实需要一个FROM子句。让我烦恼的是:Informix,Firebird和Apache Derby也需要它。
a_horse_with_no_name 2012年

1
DB2确实需要FROM子句,但是另一种选择是使用类似的语句values ('abc', 1)。您当然也可以从以下语句中进行选择:select abc from ( values ('abc',1) ) as t(abc,def)
Lennart's

Answers:


30

严格来说,是的,语句的FROM子句SELECT不是可选的。 SQL-99的语法详细说明了基本SELECT语句,该FROM子句周围没有方括号。这表明该标准认为它是非可选的:

SELECT [ DISTINCT | ALL ]
{Column expression [ AS name ]} [ ,... ] | *
FROM <Table reference> [ {,<Table reference>} ... ]
[ WHERE search condition ]
[ GROUP BY Columns [ HAVING condition ] ]
[ORDER BY {col_name | expr | position} [ASC | DESC],...]                                     
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
[PROCEDURE procedure_name(argument_list)]
[INTO OUTFILE 'file_name' export_options |
 INTO DUMPFILE 'file_name' |
 INTO var_name [, var_name]]
[FOR UPDATE | LOCK IN SHARE MODE]

在实际使用中,程序员和DBA经常发现除操作表中的数据或操作表和数据结构外,还可以执行其他操作。这种类型的事情在很大程度上超出了SQL标准的范围,SQL标准关注的是数据特性,而不是特定实现的基本要素。无论我们是要运行SELECT getdate()还是SELECT 1SELECT DB_NAME()(或您的方言喜欢的任何一种),我们实际上都不需要表中的数据。

Oracle选择使用具有以下有效定义的虚拟表来解决标准和实现上的差异:

CREATE TABLE DUAL (
  DUMMY CHAR(1)
  )

INSERT INTO DUAL (DUMMY) VALUES ('X')

其他RDBMS本质上假设如果未FROM指定,则使用虚拟表。

DUAL表历史记录在Wikipedia上:

DUAL表是由Oracle公司的Charles Weiss创建的,用于提供用于内部视图联接的表:

我将DUAL表创建为Oracle数据字典中的基础对象。从来没有想过要看到它本身,而是在期望查询的视图中使用它。想法是您可以对DUAL表进行JOIN并为表中的每一行在结果中创建两行。然后,通过使用GROUP BY,可以汇总结果联接以显示DATA扩展区和INDEX扩展区的存储量。名称DUAL似乎很适合仅从一个行创建一对行的过程。

原始的DUAL表中有两行(因此得名),但随后只有一行。


3
+1,欢迎访问dba.se。这是一个令人着迷的历史,它是一个很好的答案-希望您能被鼓励继续努力并做出更多的贡献:)
杰克说尝试topanswers.xyz 2012年

4
当开发人员在double中插入更多行时,我经历了数小时的无尽乐趣。打破了很多东西:)花了一段时间来追查罪魁祸首!
Philᵀᴹ

8

dual优化器了解到的好处是,它dual是一种特殊的单行,一列的表(具有varchar2数据类型)-在查询中使用它时,在制定计划时会使用此知识。

为什么我们需要从dualOracle中进行选择?

您也可以从dual自己的表中选择,也可以从自己的表中选择。

对我来说,我会坚持下去,dual因为我知道dual存在。我知道它至少有1行,最多1行。我知道优化器了解所有知识dual并为我做最有效的事情。优化器理解dual是一个神奇的,特殊的1行表。它停止在上,select *因为那里只有一行。所以这就是它的工作方式。


“我知道它至少有1行,最多1行。” 好吧,具有DBA特权的混蛋(或白痴)可以进行修改DUAL。小心!
Nick Chammas 2013年

好吧,那是发生在你身上。撤消此某人的所有特权,但“创建会话”除外。如果有人不小心摔倒了偶像怎么办?
DevYudh

您可以使用创建表双(虚拟varchar2(1))存储(初始1)或闪回表双创建到删除之前创建它
DevYudh 2013年

好吧,与从任何其他现有表中选择表达式相比,使用DUAL的优点是,但是它并没有说明使用DUAL替代不必具有FROM的优点,例如在PostgreSQL或SQLServer中
Danubian Sailor

@Lukasz Lech在Oracle中没有#MSSQL Serv没有FROM的SELECT:SQL Server中根本不需要双表。但是,如果您将代码从oracle转移到SQL Serv,则可以使用此脚本创建双重代码。在SQL Server中使用/创建双重表的原因。并且MSSQL Serv和PostGRE SQL不需要虚拟表
DevYudh 2013年

1

另外两个答案为我的答案提供了良好的背景。

在Oracle数据库上,它是传统且可靠的。在没有DUAL表的其他数据库上它将失败。不必使用DUAL,但我建议您使用。

符合标准的数据库将需要FROM至少指定表引用的子句。如果您有ORDERS表,则该FROM DUAL子句的以下替换将起作用:

FROM   orders
WHERE  rownum =1

替换您可以选择的任何表或视图,它将起作用。替换无法选择的表或视图,它将失败。DUAL除非DBA破坏它,否则所有用户都可以从中选择,并且在结果集中仅获得一行,因此更为可靠。(它确实偶尔会坏掉。)

我不知道用于访问不包含表引用的表中数据的符合标准的动词。鉴于我访问这些数据的机会很少,所以我认为没有必要。我遇到的许多情况可以用不同的方式更好地处理。


2
SELECT CURRENT_TIMESTAMP FROM (VALUES(1)) V(C)我相信它符合标准,并且不依赖任何特定的表。
马丁·史密斯

@MartinSmith我已更新我的响应以使用表引用。这就是我的意思,应该指定。
BillThor 2012年
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.