Cláusula “WITH” do MySQL

98

Estou tentando usar o MySQL para criar uma exibição com a cláusula "WITH"

WITH authorRating(aname, rating) AS
   SELECT aname, AVG(quantity)
   FROM book
   GROUP BY aname

Mas não parece que o MySQL suporta isso.

Achei que isso era bastante padrão e tenho certeza que o Oracle suporta isso. Existe alguma maneira de forçar o MySQL a usar a cláusula "WITH"? Eu tentei com o motor MyISAM e innoDB. Ambos não funcionam.

shA.t
fonte

Respostas:

109

Atualização: O MySQL 8.0 está finalmente obtendo o recurso de expressões de tabela comuns, incluindo CTEs recursivas.

Aqui está um blog anunciando isso: http://mysqlserverteam.com/mysql-8-0-labs-recursive-common-table-expressions-in-mysql-ctes/

Abaixo está minha resposta anterior, que escrevi originalmente em 2008.


O MySQL 5.x não oferece suporte a consultas usando a WITHsintaxe definida no SQL-99, também chamada de Expressões de tabela comuns.

Esta tem sido uma solicitação de recurso do MySQL desde janeiro de 2006: http://bugs.mysql.com/bug.php?id=16244

Outros produtos RDBMS que suportam expressões de tabela comuns:

Bill Karwin
fonte
1
SQLite suporta a cláusula WITH a partir da versão 3.8.3 lançada em 03/02/2014.
Martijn
Eu adicionei H2 e Firebird à lista.
a_horse_with_no_name
2
@BillKarwin: Não acredito que o MySQL venha a implementar qualquer recurso SGBD moderno (verificar restrições, função de janela, índice em expressões, índice parcial, restrições adiadas ...).
a_horse_with_no_name
2
@a_horse_with_no_name, eles parecem colocar uma prioridade muito maior na escalabilidade. Eles se concentraram por muito tempo em tornar seus internos mais escaláveis, para aproveitar as vantagens do hardware moderno. Mas acho que eles negligenciaram os recursos do SQL.
Bill Karwin
1
@BlakeMcBride, Você está errado, seu comentário é FUD e não tem base em fatos. A Oracle também possui outros produtos de banco de dados que fazem coisas que o Oracle DB não faz bem. Exemplos: TimesTen, BerkeleyDB. Eles adquiriram esses bancos de dados para expandir seu mercado. O MySQL é dominante no mercado de aplicativos da web, e o Oracle DB não, então eles adquiriram o MySQL. Não faz sentido para a Oracle prejudicar o MySQL. Conversei com os desenvolvedores do Oracle MySQL na conferência em abril, e eles estão de fato trabalhando na implementação do WITH para MySQL.
Bill Karwin
17

Você pode estar interessado em algo como este:

select * from (
    select * from table
) as Subquery
Mosty Mostacho
fonte
você pode explicar a Subconsulta, por favor? eu poderia ter selecionado * de ((selecione * da tabela1) UNION ALL (selecione * da tabela2)) Grupo por algo?
1
@Kathy Olá, Subqueryé o nome que usei para a própria tabela derivada. Quando você usa, from ( ... )você cria algo como uma tabela temporária (uma tabela derivada) e requer um nome. É por isso que usei as Subquery. Respondendo à sua pergunta, sim, você pode, mas você terá que colocar um nome na tabela derivada externa (logo antes de Group By). Espero que tenha ajudado.
Mosty Mostacho
@MostyMostacho Olá, poderia me dar um pouco de comida aqui? Estou lutando para convertê-lo para MySQL. Você pode dar uma olhada nisso? ligar ou responder minha pergunta aqui, talvez? link
Pranav
13

Você tem a sintaxe certa:

WITH AuthorRating(AuthorName, AuthorRating) AS
   SELECT aname         AS AuthorName,
          AVG(quantity) AS AuthorRating
   FROM Book
   GROUP By Book.aname

No entanto, como outros mencionaram, o MySQL não oferece suporte a este comando. COM foi adicionado no SQL: 1999; a versão mais recente do padrão SQL é SQL: 2008. Você pode encontrar mais algumas informações sobre bancos de dados que suportam os vários recursos do SQL: 1999 na Wikipedia .

O MySQL tradicionalmente ficou um pouco atrasado no suporte ao padrão SQL, enquanto bancos de dados comerciais como Oracle, SQL Server (recentemente) e DB2 os seguiram um pouco mais de perto. PostgreSQL também é normalmente bastante compatível com os padrões.

Você pode querer dar uma olhada no roadmap do MySQL; Não tenho certeza de quando esse recurso pode ser compatível, mas é ótimo para criar consultas de roll-up legíveis.

Ed Altorfer
fonte
9

A Oracle oferece suporte a WITH.

Seria assim.

WITH emps as (SELECT * FROM Employees)
SELECT * FROM emps WHERE ID < 20
UNION ALL
SELECT * FROM emps where Sex = 'F'

@ysth COM é difícil de pesquisar no Google porque é uma palavra comum normalmente excluída das pesquisas.

Você gostaria de examinar a documentação do SELECT para ver como funciona a fatoração de subconsulta.

Eu sei que isso não responde ao OP, mas estou limpando qualquer confusão que possa ter começado.


fonte
De qualquer maneira, não esclareceu minha confusão. Você está dizendo que não há uma cláusula WITH, mas há uma instrução WITH?
ysth
1
Ah, entendo. É uma cláusula de um select que precede o select. Ele também pode ser usado em CREATE VIEW? Como é diferente de ingressar em uma subseleção? Não vejo exemplos online em que o nome depois de WITH tenha parâmetros - como isso funciona?
ysth
1
É muito diferente. Observe que o mesmo subqry é usado duas vezes sem a necessidade de defini-lo duas vezes. Claro que você poderia copiar / colar a mesma consulta lá, mas este é um exemplo simples. Imagine se a cláusula WITH fosse aplicada em uma página e fosse usada 4 vezes na consulta principal. você apreciará então.
Vinculei aos documentos, que devem explicar a sintaxe. Tanto quanto em uma vista. Claro que funciona lá.
3

Com base na resposta de @Mosty Mostacho, aqui está como você pode fazer algo equivalente no MySQL, para um caso específico de determinar quais entradas não existem em uma tabela e não estão em nenhum outro banco de dados.

select col1 from (
   select 'value1' as col1 union
   select 'value2' as col1 union
   select 'value3' as col1
) as subquery
left join mytable as mytable.mycol = col1
where mytable.mycol is null
order by col1

Você pode usar um editor de texto com recursos de macro para converter uma lista de valores para a cláusula de união selecionada entre aspas.

Reuben
fonte
1
   WITH authorRating as (select aname, rating from book)
   SELECT aname, AVG(quantity)
   FROM authorRating
   GROUP BY aname
Mantas Dainys
fonte
0

Você já experimentou a Tabela Temporária? Isso resolveu minha conversão:

create temporary table abc (
column1 varchar(255)
column2 decimal
);
insert into abc
select ...
or otherwise
insert into abc
values ('text', 5.5), ('text2', 0815.8);

Então você pode usar esta tabela em cada seleção nesta sessão:

select * from abc inner join users on ...;
Noel
fonte
1
Devo observar: stackoverflow.com/questions/343402/… você não pode abrir a Tabela duas vezes :-(
Claus
Minha solução para pequenos conjuntos de dados em tabelas: crie a tabela abc2 como abc; inserir em abc2 selecionar * de abc;
Natal