Por que tenho que selecionar na tabela dupla?

15

Isso funciona nos principais Sistemas de Gerenciamento de Banco de Dados de Relação com maior probabilidade de aparecer no StackOverflow / dba.stackexchange, sendo SQL Server, MySQL, PostgreSQL e SQLite (WebSQL) .

select 'abc' abc, 1 def;

Não funciona no Oracle. Por que precisamos selecionar DUAL no Oracle? O padrão ISO / ANSI para SQL requer uma cláusula FROM para instruções SELECT ?


Editar:

Por Bacon Bitresposta, parece exigido pelo padrão SQL.

Então, na realidade, como o nome DUAL é um nome impróprio, se eu criar uma tabela e nomeá-la como ATOM ou ONE, por exemplo create table one (atom int);... select 'abc' abc, 1 def FROM one;- Existe uma penalidade de desempenho em comparação com SELECT .. FROM DUAL?

孔夫子
fonte
Eu acho que o DB2 também não pode fazer um selectsem um from. O DB2 possui uma tabela fictícia semelhante chamada SYSIBM.SYSDUMMY1 . Você provavelmente já sabe disso, mas, quando você select 'A' from dual, a dualtabela não é realmente acessada , o que responde à pergunta em sua edição (que merecia uma nova pergunta).
11118 Jack Douglas12:
1
Ele não funciona no DBMS "todos". Existem vários DBMS que não permitem um SELECT sem um FROM. O manual responde a sua pergunta sobre o desempenho: docs.oracle.com/cd/E11882_01/server.112/e26088/...
a_horse_with_no_name
3
@JackDouglas: Você está correto. O DB2 requer uma FROMcláusula. Em cima da minha cabeça: Informix, Firebird e Apache Derby também exigem.
A_horse_with_no_name 12/11/2012
1
O DB2 requer uma cláusula FROM, mas uma alternativa é usar uma instrução como values ('abc', 1). Obviamente, você também pode selecionar uma dessas afirmações:select abc from ( values ('abc',1) ) as t(abc,def)
Lennart

Respostas:

30

Estritamente, sim, a FROMcláusula de uma SELECTdeclaração não é opcional. A sintaxe do SQL-99 detalha a SELECTdeclaração básica e a FROMcláusula não possui colchetes. Isso indica que o padrão considera não opcional:

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]

No uso real, programadores e DBAs costumam achar útil fazer outras coisas além de manipular dados em tabelas ou manipular tabelas e estruturas de dados. Esse tipo de coisa está muito além do escopo do padrão SQL, que se preocupa mais com os recursos de dados do que com as porcas e parafusos de implementações específicas. Quer desejemos executar SELECT getdate()ou SELECT 1ou SELECT DB_NAME()(ou o que seu dialeto preferir), na verdade não queremos dados de uma tabela.

A Oracle decide resolver a discrepância padrão e de implementação usando uma tabela fictícia com a seguinte definição efetiva:

CREATE TABLE DUAL (
  DUMMY CHAR(1)
  )

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

Outros RDBMSs assumem essencialmente que uma tabela fictícia será usada se não FROMfor especificado.

A história da tabela DUAL está na Wikipedia:

A tabela DUAL foi criada por Charles Weiss, da Oracle Corporation, para fornecer uma tabela para ingressar em visualizações internas:

Criei a tabela DUAL como um objeto subjacente no Oracle Data Dictionary. Ele nunca foi concebido para ser visto em si, mas usado dentro de uma exibição que se esperava que fosse consultada. A ideia era que você pudesse fazer uma JOIN na tabela DUAL e criar duas linhas no resultado para cada linha da sua tabela. Em seguida, usando GROUP BY, a junção resultante pode ser resumida para mostrar a quantidade de armazenamento para a extensão DATA e para a extensão INDEX. O nome, DUAL, parecia adequado para o processo de criação de um par de linhas a partir de apenas uma.

A tabela DUAL original tinha duas linhas (daí o nome), mas subseqüentemente ela só tinha uma linha.

Pedaços de bacon
fonte
3
+1 e bem-vindo ao dba.se. Esta é uma excelente resposta com um pouco fascinante da história, espero que você pode ser encorajados a ficar por aqui e contribuir mais :)
Jack Douglas
4
Horas de diversão sem fim foram vividas por mim uma vez, quando um desenvolvedor inseriu mais algumas linhas no dual. Quebrou muitas coisas :) Demorou um pouco para rastrear o culpado!
Philᵀᴹ
8

A vantagem dualé que o otimizador entende que dualé uma tabela especial de uma linha, uma coluna (com varchar2tipo de dados) - quando você o usa em consultas, ele usa esse conhecimento ao desenvolver o plano.

Por que precisamos selecionar dualno Oracle?

Você também pode selecionar de dualou a partir de suas próprias tabelas, se desejar.

Para mim, continuarei dualporque sei que dualexiste. Eu sei que tem pelo menos 1 e no máximo 1 linha. Eu sei que o otimizador sabe tudo duale faz a coisa mais eficiente para mim. O otimizador entende que dualé uma tabela mágica especial de 1 linha. Parou no select *porque há uma linha lá. Então é assim que funciona.

DevYudh
fonte
"Eu sei que tem pelo menos 1 e no máximo 1 linha". Bem, um idiota (ou um idiota) com privilégios de DBA pode modificarDUAL . Seja cuidadoso!
31413 Nick Chammas
Bem, se isso acontecer com você. revogar todos os privilégios, exceto CREATE SESSION dessa pessoa. e se o dual fosse descartado acidentalmente por alguém?
precisa saber é o seguinte
você pode criá-lo usando criar a tabela dupla (varchar2 manequim (1)) de armazenamento (1 inicial) ou tabela de flashback dupla para antes de queda
DevYudh
Bem, é uma vantagem usar o DUAL em comparação à seleção da expressão de qualquer outra tabela existente, mas não explica qual é a vantagem de ter o DUAL como alternativa por não ter do FROM, como no PostgreSQL ou SQLServer
Danubian Sailor
@Lukasz Lech no Oracle, não há SELECT sem FROM para o #MSSQL Serv: não há necessidade de tabela dupla no SQL Server. mas se você transferiu seu código do oracle para o SQL Serv, você pode criar dual usando este script CREATE TABLE DUAL (DUMMY VARCHAR (1)) INSERIR DUAS VALORES DUMMY ('X') GO, mas não vejo nenhum razão para usar / criar tabela dupla no servidor sql. e também MSSQL Serv e PostGRE SQL não requerem tabela Dummy
DevYudh
1

As outras duas respostas fornecem bons antecedentes para a minha resposta.

Nos bancos de dados Oracle, é tradicional e confiável. Ele falhará em outros bancos de dados que não possuem uma DUALtabela. Não é necessário que você use DUAL, mas eu recomendaria.

Os bancos de dados compatíveis com os padrões exigirão uma FROMcláusula que especifique pelo menos a referência da tabela. Se você tiver uma tabela ORDERS, a seguinte substituição para a FROM DUALcláusula funcionaria:

FROM   orders
WHERE  rownum =1

Substitua qualquer tabela ou exibição da qual você possa selecionar e ele funcionará. Substitua uma tabela ou exibição da qual você não pode selecionar e ela falhará. DUALé mais confiável, exceto quando um DBA é interrompido, todos os usuários podem selecionar e obterão apenas uma linha no conjunto de resultados. (Ele se quebra ocasionalmente.)

Não conheço um verbo compatível com os padrões para acessar dados que não estão em uma tabela sem incluir uma referência a tabela. Dado o pouco acesso a esses dados, não vejo essa necessidade. Muitos dos casos em que encontro, podem ser melhor tratados de maneiras diferentes.

BillThor
fonte
2
SELECT CURRENT_TIMESTAMP FROM (VALUES(1)) V(C)é compatível com os padrões e acredito que não depende de nenhuma tabela específica.
Martin Smith
@ MartinSmith Atualizei minha resposta para usar a referência de tabela. Isto é o que eu quis dizer e deveria ter especificado.
BillThor