Klausa MySQL “WITH”

98

Saya mencoba menggunakan MySQL untuk membuat tampilan dengan klausa "DENGAN"

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

Tapi sepertinya MySQL tidak mendukung ini.

Saya pikir ini cukup standar dan saya yakin Oracle mendukung ini. Apakah ada cara untuk memaksa MySQL menggunakan klausa "WITH"? Saya sudah mencobanya dengan mesin MyISAM dan innoDB. Keduanya tidak berfungsi.

shA.t
sumber

Jawaban:

109

Pembaruan: MySQL 8.0 akhirnya mendapatkan fitur ekspresi tabel umum, termasuk CTE rekursif.

Berikut adalah blog yang mengumumkannya: http://mysqlserverteam.com/mysql-8-0-labs-recursive-common-table-expressions-in-mysql-ctes/

Di bawah ini adalah jawaban saya sebelumnya, yang awalnya saya tulis pada tahun 2008.


MySQL 5.x tidak mendukung kueri menggunakan WITHsintaks yang ditentukan dalam SQL-99, juga disebut Ekspresi Tabel Umum.

Ini telah menjadi permintaan fitur untuk MySQL sejak Januari 2006: http://bugs.mysql.com/bug.php?id=16244

Produk RDBMS lain yang mendukung ekspresi tabel umum:

Bill Karwin
sumber
1
SQLite mendukung klausa WITH pada versi 3.8.3 yang dirilis pada 2014-02-03.
Martijn
Saya menambahkan H2 dan Firebird ke daftar.
a_horse_with_no_name
2
@BillKarwin: Saya tidak percaya MySQL akan pernah menerapkan setiap DBMS modern memiliki (kendala cek, fungsi jendela, indeks pada ekspresi, indeks parsial, kendala ditangguhkan ...).
a_horse_with_no_name
2
@a_horse_with_no_name, mereka tampaknya menempatkan prioritas yang jauh lebih tinggi pada skalabilitas. Mereka telah lama berfokus untuk membuat internal mereka lebih skalabel, untuk memanfaatkan perangkat keras modern. Tapi saya pikir mereka telah mengabaikan fitur SQL.
Bill Karwin
1
@BlakeMcBride, Anda salah, komentar Anda adalah FUD dan sebenarnya tidak memiliki dasar. Oracle juga memiliki produk database lain yang melakukan hal-hal yang tidak dilakukan Oracle DB dengan baik. Contoh: TimesTen, BerkeleyDB. Mereka memperoleh database tersebut untuk memperluas pasar mereka. MySQL dominan di pasar aplikasi web, dan Oracle DB tidak, jadi mereka mengakuisisi MySQL. Tidak masuk akal bagi Oracle untuk melakukan hamstring MySQL. Saya berbicara dengan pengembang Oracle MySQL di konferensi pada bulan April, dan mereka sebenarnya sedang mengerjakan implementasi WITH untuk MySQL.
Bill Karwin
17

Anda mungkin tertarik dengan pemikiran seperti ini:

select * from (
    select * from table
) as Subquery
Mosty Mostacho
sumber
bisakah Anda menjelaskan Subquery? dapatkah saya memilih * dari ((pilih * dari tabel1) UNION SEMUA (pilih * dari tabel2)) Kelompokkan dengan sesuatu?
1
@Ky Hai, Subqueryadalah nama yang saya gunakan untuk tabel turunan itu sendiri. Saat Anda menggunakan from ( ... )Anda membuat sesuatu seperti tabel sementara (tabel turunan) dan itu membutuhkan nama. Itu sebabnya saya menggunakan as Subquery. Menjawab pertanyaan Anda, ya, Anda bisa, tetapi Anda harus memberi nama pada tabel turunan luar (tepat sebelum Group By). Semoga membantu.
Mosty Mostacho
@MostyMostacho Halo, dapatkah saya menyuapi saya sedikit di sini? Saya kesulitan untuk mengubahnya menjadi MySQL. Bisakah kamu melihatnya? tautkan atau jawab pertanyaan saya di sini mungkin? tautan
Pranav
13

Anda memiliki sintaks yang benar:

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

Namun, seperti yang disebutkan orang lain, MySQL tidak mendukung perintah ini. DENGAN ditambahkan di SQL: 1999; versi terbaru dari standar SQL adalah SQL: 2008. Anda dapat menemukan beberapa informasi lebih lanjut tentang database yang mendukung berbagai fitur SQL: 1999 di Wikipedia .

MySQL secara tradisional sedikit tertinggal dalam dukungan untuk standar SQL, sedangkan database komersial seperti Oracle, SQL Server (baru-baru ini), dan DB2 telah mengikuti mereka sedikit lebih dekat. PostgreSQL biasanya cukup memenuhi standar juga.

Anda mungkin ingin melihat peta jalan MySQL; Saya tidak sepenuhnya yakin kapan fitur ini mungkin didukung, tetapi sangat bagus untuk membuat kueri tersingsing yang dapat dibaca.

Ed Altorfer
sumber
10

Oracle mendukung WITH.

Ini akan terlihat seperti ini.

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

@ysth WITH sulit untuk Google karena ini adalah kata umum yang biasanya dikecualikan dari pencarian.

Anda ingin melihat dokumen SELECT untuk melihat cara kerja pemfaktoran subkueri.

Saya tahu ini tidak menjawab OP tetapi saya sedang membersihkan kebingungan yang mungkin telah dimulai.


sumber
Tidak menjernihkan kebingungan saya. Apakah Anda mengatakan bahwa tidak ada klausa WITH tetapi ada pernyataan WITH?
ysth
1
Ah, begitu. Ini adalah klausa pemilihan yang mendahului pemilihan. Bisakah ini digunakan dalam CREATE VIEW juga? Apa bedanya dengan bergabung dengan subselect? Saya tidak melihat contoh online di mana nama setelah WITH memiliki parameter - bagaimana cara kerjanya?
ysth
1
Ini sangat berbeda. Perhatikan bahwa subqry yang sama digunakan dua kali tanpa harus mendefinisikannya dua kali. Tentu Anda bisa menyalin / menempelkan kueri yang sama di sana tetapi ini adalah contoh sederhana. Bayangkan jika klausa WITH berlanjut untuk sebuah halaman dan digunakan 4 kali di kueri utama. Anda akan menghargainya nanti.
Saya menautkan ke dokumen, yang seharusnya menjelaskan sintaksnya. Sejauh dalam pandangan. Yakin itu berhasil di sana.
3

Berdasarkan jawaban dari @Mosty Mostacho, berikut ini cara Anda melakukan sesuatu yang setara di MySQL, untuk kasus tertentu dalam menentukan entri apa yang tidak ada dalam tabel, dan tidak ada di database lain.

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

Anda mungkin ingin menggunakan editor teks dengan kemampuan makro untuk mengonversi daftar nilai menjadi klausa gabungan pemilihan yang dikutip.

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

Apakah Anda pernah mencoba Tabel Sementara? Ini memecahkan masalah saya:

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

Kemudian Anda dapat menggunakan tabel ini di setiap pilihan di sesi ini:

select * from abc inner join users on ...;
Claus
sumber
1
Saya harus mencatat: stackoverflow.com/questions/343402/… Anda tidak dapat membuka Tabel dua kali :-(
Claus
Solusi Saya untuk kumpulan data kecil dalam tabel: buat tabel abc2 seperti abc; masukkan ke dalam abc2 pilih * dari abc;
Claus