MySQL 8 mendukung ekspresi tabel umum, baik non-rekursif dan rekursif, A CTE (Common Table Expression) adalah kumpulan hasil sementara yang dapat Anda rujuk dalam pernyataan SELECT, INSERT, UPDATE, atau DELETE lainnya.
CTE non-rekursif
Ekspresi tabel umum (CTE) sama seperti tabel turunan, tetapi deklarasinya diletakkan sebelum blok kueri alih-alih dalam klausa FROM. Menggunakan CTE, subquery dievaluasi hanya sekali, Ekspresi tabel umum memungkinkan penggunaan set hasil sementara bernama, Ekspresi Tabel Umum didefinisikan dalam pernyataan menggunakan operator WITH.
Misalkan Anda ingin mengetahui persentase perubahan pembayaran setiap tahun sehubungan dengan tahun sebelumnya. Tanpa CTE, Anda perlu menulis dua subkueri, dan keduanya pada dasarnya sama. MySQL tidak cukup pintar untuk mendeteksinya dan subquery dieksekusi dua kali.
SELECT q1.years,q2.years AS next_year,q1.sum1,q2.sum1 AS next_sum,100 * (q2.sum1 - q1.sum1) / q1.sum1 AS pctFROM(SELECT YEAR(paymentDate) AS tahun, SUM(jumlah) SEBAGAI sum1 DARI pembayaran KELOMPOK MENURUT tahun) SEBAGAI q1,(PILIH TAHUN(Tanggal Pembayaran) SEBAGAI tahun, SUM(jumlah) SEBAGAI sum1 DARI pembayaran KELOMPOK MENURUT tahun) SEBAGAI q2WHEREq1.years =q2.years - 1;+-- -----+-----------+------------+------------+------ ------+| tahun | tahun_berikutnya | jumlah1 | jumlah_berikutnya | persen |+-------+-----------+------------+------------+- -----------+| 2003 | 2004 | 3250217,70 | 4313328.25 | 32.708903 || 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 |+-------+-----------+------------+------------+ ------------+2 baris dalam set (0,01 detik)
Dengan CTE non-rekursif, kueri turunan dieksekusi hanya sekali dan digunakan kembali
DENGAN CTE_NAME AS (PILIH TAHUN(Tanggal Pembayaran) SEBAGAI tahun, SUM(jumlah) SEBAGAI sum1 DARI pembayaran KELOMPOK MENURUT tahun)PILIH q1.years,q2.years AS next_year,q1.sum1,q2.sum1 AS next_sum,100 * (q2.sum1 - q1.sum1) / q1.sum1 AS persen DARI CTE_NAME AS q1,CTE_NAME AS q2 WHERE q1.years =q2.years - 1;+-------+------- ----+------------+------------+------------+| tahun | tahun_berikutnya | jumlah1 | jumlah_berikutnya | persen |+-------+-----------+------------+------------+- -----------+| 2003 | 2004 | 3250217,70 | 4313328.25 | 32.708903 || 2004 | 2005 | 4313328.25 | 1290293.28 | -70.085901 |+-------+-----------+------------+------------+ ------------+2 baris dalam set (0,00 detik)
Anda mungkin memperhatikan bahwa dengan CTE, hasilnya sama dan waktu kueri meningkat 50%, keterbacaannya bagus dan dapat dirujuk beberapa kali
CTE dapat merujuk ke CTE lain:DENGAN cte1 AS (SELECT ... FROM ...), cte2 AS (SELECT ... FROM cte1 ...)SELECTFROM cte1, cte2 ...
CTE rekursif
CTE rekursif adalah CTE yang mereferensikan dirinya sendiri. Dengan demikian, CTE awal dijalankan berulang kali, mengembalikan subset data, hingga hasil lengkap dikembalikan
DENGAN cte_name AS RECURSIVE (cte_definition -- /* seed SELECT */UNION ALLcte_definition -- /* "recursive" SELECT */ references cte_name.)-- Pernyataan menggunakan CTESELECT *FROM cte_name
Seed SELECT dijalankan sekali untuk membuat subset data awal; SELECT rekursif dijalankan berulang kali untuk mengembalikan subset data hingga set hasil lengkap diperoleh. Rekursi berhenti ketika iterasi tidak menghasilkan baris baru.
Misalkan Anda ingin melakukan penelusuran data hierarkis untuk menghasilkan bagan organisasi dengan rantai manajemen untuk setiap karyawan (yaitu, jalur dari CEO ke karyawan). Gunakan CTE rekursif! CTE rekursif sangat cocok untuk menanyakan data hierarkis,
Buat tabel
BUAT TABEL mangeremp (id INT PRIMARY KEY NOT NULL,nama VARCHAR(100) NOT NULL,man_id INT NULL,INDEX (man_id),FOREIGN KEY (man_id) REFERENSI mangeremp (id));
menyisipkan data untuk mendapatkan struktur hierarki
INSERT INTO mangeremp VALUES(333, "waqas", NULL), # waqas adalah CEO (man_id adalah NULL)(198, "ali", 333), # ali memiliki ID 198 dan melapor ke 333 (waqas)( 692, "ahmed", 333), #ahmed lapor ke waqas(29, "oasama", 198), #osama lapor ke ali as alo has ref id 198(4610, "Mughee", 29), # Mughee lapor ke osama (72, "aslam", 29),(123, "afrooz", 692);
DENGAN emp_paths RECURSIVE (id, name, path) AS (SELECT id, name, CAST(id AS CHAR(200)) FROM mangeremp WHERE man_id IS NULL UNION ALL SELECT e.id, e.name, CONCAT(ep. path, ',', e.id) FROM emp_paths AS ep GABUNG mangeremp AS e ON ep.id =e.man_id )SELECT * FROM emp_paths ORDER BY path;+------+------- --+-----------------+| id | nama | jalur |+------+--------+-------+| 333 | waqa | 333 || 198 | ali | 333.198 || 29 | oasama | 333.198,29 || 4610 | Mughee | 333.198.29.4610 || 72 | aslam | 333.198,29,72 || 692 | ahmed | 333,692 || 123 | afrooz | 333.692.123 |+------+---------+-----------------+7 baris di set (0,00 detik)
PILIH e.id, e.name, CONCAT(ep.path, ',', e.id) FROM emp_paths AS ep JOIN mangeremp AS e ON ep.id =e.man_id ---- query rekursifSetiap baris yang dihasilkan oleh kueri rekursif menemukan semua karyawan yang melapor langsung ke
karyawan yang dihasilkan oleh baris sebelumnya. Untuk setiap karyawan tersebut, baris tersebut menyertakan
ID karyawan, nama, dan rantai manajemen karyawan. Rantai adalah rantai manajer
dengan ID karyawan ditambahkan di akhir