Seperti yang telah disarankan orang lain, kami biasanya menghindari mengulang melalui kumpulan hasil RBAR (baris demi baris yang menyiksa) terutama untuk alasan kinerja. Kami hanya tidak ingin membiasakan diri mengulang-ulang hasil. Tapi itu tidak menjawab pertanyaan yang Anda ajukan.
Untuk menjawab pertanyaan yang Anda ajukan, berikut adalah contoh dasar dari program tersimpan MySQL yang menggunakan CURSOR untuk memproses baris yang dikembalikan oleh kueri satu per satu. MySQL tidak mendukung blok anonim, jadi satu-satunya cara untuk melakukannya adalah dalam program tersimpan MySQL, seperti PROSEDUR
DELIMITER $$
CREATE PROCEDURE loop_through_var_list
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_id INT DEFAULT NULL;
DECLARE csr_var_list CURSOR FOR SELECT id FROM var_list ORDER BY id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN csr_var_list;
get_id: LOOP
FETCH csr_var_list INTO v_id;
IF done = 1 THEN
LEAVE get_id;
END IF;
-- at this point, we have an id value in v_id, so we can do whatever
SET @s1 = CONCAT('SELECT ... WHERE id =''', v_id, ''' ...');
END LOOP get_id;
CLOSE csr_var_list;
END$$
DELIMITER ;
Untuk menjalankan prosedur:
CALL loop_through_var_list();
CATATAN:Sintaks untuk memproses CURSOR di MySQL sedikit berbeda dari database lain.
Untuk mendapatkan "perulangan", kita perlu menggunakan LOOP ... END LOOP
konstruksi.
Namun untuk mencegah loop tersebut berjalan selamanya, kita memerlukan pernyataan LEAVE yang memungkinkan kita untuk keluar dari loop.
Kami menggunakan tes bersyarat untuk menentukan kapan harus pergi. Dalam contoh ini, kita ingin keluar setelah kita selesai memproses baris terakhir.
FETCH
akan mengeluarkan pengecualian ketika tidak ada lagi baris yang akan diambil.
Kami "menangkap" pengecualian itu dalam CONTINUE HANDLER (untuk beberapa alasan misterius, "penangan" harus mendeklarasikan hal-hal terakhir; MySQL membuat kesalahan jika kami mencoba mendeklarasikan sesuatu setelah HANDLER (selain HANDLER lain.)
Ketika MySQL melempar pengecualian "tidak ada lagi baris", itu akan mengaktifkan kode handler. Dalam contoh ini, kami hanya mengatur variabel (bernama done
) ke suatu nilai.
Karena ini adalah handler "lanjutkan", pemrosesan dimulai kembali pada pernyataan di mana pengecualian dilemparkan, dalam hal ini, itu akan menjadi pernyataan setelah FETCH. Jadi, hal pertama yang kita lakukan adalah memeriksa apakah kita sudah "selesai" atau belum. Jika kita "selesai", maka kita keluar dari loop, dan menutup kursor.
Jika tidak, kami tahu bahwa kami memiliki id
nilai dari var_list
disimpan dalam variabel prosedur bernama v_id
. Jadi sekarang kita bisa melakukan apapun yang kita mau. Sepertinya Anda ingin memasukkan beberapa teks SQL ke dalam variabel yang ditentukan pengguna (termasuk nilai v_id ke dalam teks SQL, lalu PREPARE, EXECUTE, dan DEALLOCATE PREPARE.
Pastikan untuk mendeklarasikan v_id
variabel dengan tipe data yang sesuai, yang cocok dengan tipe data id
kolom di var_list
, saya baru saja berasumsi bahwa itu adalah INT.
Saat kita mencapai akhir loop, MySQL "mengulang" kembali ke awal loop, dan kita mulai lagi.
Di badan loop, kemungkinan Anda ingin CONCAT v_id ke dalam teks SQL yang ingin Anda jalankan. Sepertinya Anda sudah memiliki pegangan pada PREPARE, DEALLOCATE mempersiapkan. Untuk pengujian, Anda mungkin ingin menambahkan klausa LIMIT pada SELECT dalam deklarasi kursor, dan kemudian melakukan v_id SELECT sederhana; di isi, hanya untuk memverifikasi loop berfungsi, sebelum Anda menambahkan lebih banyak kode.
TINDAK LANJUT
Saya ingin menyebutkan pendekatan alternatif lain untuk tugas tersebut, yaitu menjalankan serangkaian pernyataan berdasarkan template, menggantikan nilai yang diberikan dari satu pernyataan pilih SQL...
Misalnya, jika saya memiliki template ini:
SELECT *
INTO OUTFILE '/tmp/[email protected]'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM data
WHERE id = @ID
ORDER BY 1
dan saya perlu mengganti kemunculan @ID dengan nilai id tertentu dari daftar yang dikembalikan dari pernyataan SELECT, mis.
SELECT id
FROM var_list
WHERE id IS NOT NULL
GROUP BY id
Saya mungkin tidak akan menggunakan program tersimpan MySQL dengan loop CURSOR, saya akan menggunakan pendekatan yang berbeda.
Saya akan menggunakan pernyataan SELECT untuk menghasilkan satu set pernyataan SQL yang dapat dieksekusi. Dengan asumsi id
adalah tipe integer, saya mungkin akan melakukan sesuatu seperti ini:
SELECT CONCAT(' SELECT *
INTO OUTFILE ''/tmp/orders_',s.id,'.csv''
FIELDS TERMINATED BY '','' ENCLOSED BY ''"''
LINES TERMINATED BY ''\n''
FROM data
WHERE id = ',s.id,'
ORDER BY 1;') AS `stmt`
FROM ( SELECT v.id
FROM var_list v
WHERE v.id IS NOT NULL
GROUP BY v.id
) s
ORDER BY s.id
Untuk setiap nilai id
dikembalikan dari s
, pernyataan mengembalikan teks pernyataan SQL SELECT yang dapat (dan perlu) dijalankan. Menangkapnya ke dalam file teks akan memberi saya skrip SQL yang bisa saya jalankan.