Clausola "WITH" di MySQL


98

Sto cercando di utilizzare MySQL per creare una vista con la clausola "WITH"

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

Ma non sembra che MySQL lo supporti.

Ho pensato che fosse abbastanza standard e sono sicuro che Oracle lo supporti. Esiste comunque per forzare MySQL a utilizzare la clausola "WITH"? L'ho provato con il motore MyISAM e innoDB. Entrambi questi non funzionano.

Risposte:


109

Aggiornamento: MySQL 8.0 sta finalmente ottenendo la funzionalità delle espressioni di tabella comuni, inclusi i CTE ricorsivi.

Ecco un blog che lo annuncia: http://mysqlserverteam.com/mysql-8-0-labs-recursive-common-table-expressions-in-mysql-ctes/

Di seguito è la mia risposta precedente, che ho scritto originariamente nel 2008.


MySQL 5.x non supporta le query che utilizzano la WITHsintassi definita in SQL-99, chiamata anche Common Table Expressions.

Questa è stata una richiesta di funzionalità per MySQL dal gennaio 2006: http://bugs.mysql.com/bug.php?id=16244

Altri prodotti RDBMS che supportano espressioni di tabella comuni:


1
SQLite supporta la clausola WITH a partire dalla versione 3.8.3 rilasciata il 03/02/2014.
Martijn

Ho aggiunto H2 e Firebird all'elenco.
a_horse_with_no_name

2
@ BillKarwin: Non credo che MySQL implementerà mai alcuna funzionalità DBMS moderna (controlli vincoli, funzione finestra, indice sulle espressioni, indice parziale, vincoli differiti ...).
a_horse_with_no_name

2
@a_horse_with_no_name, sembrano attribuire una priorità molto più alta alla scalabilità. Si sono concentrati a lungo sul rendere i loro interni più scalabili, per sfruttare l'hardware moderno. Ma penso che abbiano trascurato le funzionalità SQL.
Bill Karwin

1
@BlakeMcBride, ti sbagli, il tuo commento è FUD e non ha fondamento. Oracle possiede anche altri prodotti di database che fanno cose che Oracle DB non fa bene. Esempi: TimesTen, BerkeleyDB. Hanno acquisito quei database per espandere il loro mercato. MySQL è dominante nel mercato delle applicazioni web e Oracle DB no, quindi hanno acquisito MySQL. Non ha senso per Oracle ostacolare MySQL. Ho parlato con gli sviluppatori Oracle MySQL alla conferenza di aprile e stanno lavorando per implementare WITH per MySQL.
Bill Karwin

17

Potresti essere interessato a qualcosa del genere:

select * from (
    select * from table
) as Subquery

puoi spiegare Subquery per favore? potrei selezionare * da ((seleziona * da tabella1) UNION ALL (seleziona * da tabella2)) Gruppo per qualcosa?

1
@Kathy Ciao, Subqueryè il nome che ho usato per la tabella derivata stessa. Quando usi from ( ... )crei qualcosa come una tabella temporanea (una tabella derivata) e richiede un nome. Ecco perché ho usato as Subquery. Rispondendo alla tua domanda, sì, puoi, ma dovrai dare un nome alla tabella derivata esterna (appena prima del Group By). Spero che abbia aiutato.
Mosty Mostacho

@MostyMostacho Ciao, potresti darmi da mangiare un po 'qui per favore? Sto lottando per convertirlo in MySQL. Puoi dargli un'occhiata? link o rispondere alla mia domanda qui forse? link
Pranav

13

Hai la sintassi giusta:

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

Tuttavia, come altri hanno già detto, MySQL non supporta questo comando. WITH è stato aggiunto in SQL: 1999; la versione più recente dello standard SQL è SQL: 2008. Puoi trovare ulteriori informazioni sui database che supportano le varie funzionalità di SQL: 1999 su Wikipedia .

MySQL è tradizionalmente un po 'in ritardo nel supporto per lo standard SQL, mentre database commerciali come Oracle, SQL Server (recentemente) e DB2 li hanno seguiti un po' più da vicino. PostgreSQL è in genere anche abbastanza conforme agli standard.

Potresti voler guardare la roadmap di MySQL; Non sono completamente sicuro di quando questa funzione potrebbe essere supportata, ma è ottima per creare query di roll-up leggibili.


10

Oracle supporta WITH.

Sarebbe così.

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

@ysth WITH è difficile da google perché è una parola comune tipicamente esclusa dalle ricerche.

Ti consigliamo di guardare i documenti SELECT per vedere come funziona la fattorizzazione delle sottoquery.

So che questo non risponde all'OP ma sto ripulendo qualsiasi confusione che potrebbe essere iniziata.


Comunque non ha chiarito la mia confusione. Stai dicendo che non c'è una clausola WITH ma c'è un'istruzione WITH?
ysth

1
Ah, capisco. È una clausola di una selezione che precede la selezione. Può essere utilizzato anche in CREATE VIEW? In che modo è diverso dall'unirsi a una sottoselezione? Non vedo esempi online in cui il nome dopo il WITH abbia parametri: come funzionano?
ysth

1
È molto diverso. Si noti che la stessa subqry viene utilizzata due volte senza doverla definire due volte. Sicuramente potresti copiare / incollare la stessa query, ma questo è un semplice esempio. Immagina se la clausola WITH continuasse per una pagina e fosse utilizzata 4 volte nella query principale. lo apprezzerai allora.

Mi sono collegato alla documentazione, che dovrebbe spiegare la sintassi. Per quanto riguarda la vista. Certo che funziona lì.

3

Basandosi sulla risposta di @Mosty Mostacho, ecco come potresti fare qualcosa di equivalente in MySQL, per un caso specifico di determinare quali voci non esistono in una tabella e non sono in nessun altro database.

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

È possibile utilizzare un editor di testo con funzionalità macro per convertire un elenco di valori nella clausola di unione di selezione tra virgolette.



1
   WITH authorRating as (select aname, rating from book)
   SELECT aname, AVG(quantity)
   FROM authorRating
   GROUP BY aname

0

Hai mai provato Temporary Table? Questo ha risolto il mio problema:

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);

Quindi puoi utilizzare questa tabella in ogni selezione in questa sessione:

select * from abc inner join users on ...;

1
Devo notare: stackoverflow.com/questions/343402/… non puoi aprire la tabella due volte :-(
Claus

My Sollution per piccoli set di dati nelle tabelle: crea la tabella abc2 come abc; inserisci in abc2 seleziona * da abc;
Claus
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.