Tidak, tidak dalam satu pernyataan.
Untuk mendapatkan nama semua tabel yang berisi kolom bernama Foo
:
SELECT table_schema, table_name
FROM information_schema.columns
WHERE column_name = 'Foo'
Kemudian, Anda memerlukan pernyataan UPDATE untuk setiap tabel. (Dimungkinkan untuk memperbarui beberapa tabel dalam satu pernyataan, tetapi itu harus menjadi gabungan silang (tidak perlu).) Lebih baik lakukan setiap tabel secara terpisah.
Anda dapat menggunakan SQL dinamis untuk mengeksekusi pernyataan UPDATE dalam program tersimpan MySQL (mis. PROSEDUR)
DECLARE sql VARCHAR(2000);
SET sql = 'UPDATE db.tbl SET Foo = 0';
PREPARE stmt FROM sql;
EXECUTE stmt;
DEALLOCATE stmt;
Jika Anda mendeklarasikan kursor untuk pilih dari information_schema.tables, Anda dapat menggunakan loop kursor untuk memproses UPDATE
dinamis pernyataan untuk setiap nama_tabel yang dikembalikan.
DECLARE done TINYINT(1) DEFAULT FALSE;
DECLARE sql VARCHAR(2000);
DECLARE csr FOR
SELECT CONCAT('UPDATE `',c.table_schema,'`.`',c.table_name,'` SET `Foo` = 0') AS sql
FROM information_schema.columns c
WHERE c.column_name = 'Foo'
AND c.table_schema NOT IN ('mysql','information_schema','performance_schema');
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN csr;
do_foo: LOOP
FETCH csr INTO sql;
IF done THEN
LEAVE do_foo;
END IF;
PREPARE stmt FROM sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP do_foo;
CLOSE csr;
(Ini hanya gambaran kasar dari sebuah contoh, bukan sintaks yang diperiksa atau diuji.)
TINDAK LANJUT
Beberapa catatan singkat tentang beberapa ide yang mungkin disamarkan dalam jawaban di atas.
Untuk mendapatkan nama tabel yang berisi kolom Foo
, kita dapat menjalankan kueri dari information_schema.columns
meja. (Itu salah satu tabel yang disediakan di information_schema
MySQL basis data.)
Karena kita mungkin memiliki tabel di beberapa database, nama_tabel tidak cukup untuk mengidentifikasi tabel; kita perlu tahu database tempat tabel itu berada. Daripada mengacaukan "use db
" sebelum kita menjalankan UPDATE
, kita bisa mereferensikan tabel UPDATE db.mytable SET Foo...
.
Kita dapat menggunakan kueri information_schema.columns
untuk melanjutkan dan merangkai (menggabungkan) bagian-bagian yang perlu kita buat untuk pernyataan UPDATE, dan meminta SELECT mengembalikan pernyataan aktual yang perlu kita jalankan untuk memperbarui kolom Foo
, pada dasarnya ini:
UPDATE `mydatabase`.`mytable` SET `Foo` = 0
Tapi kami ingin mengganti nilai dari table_schema
dan table_name
sebagai pengganti mydatabase
dan mytable
. Jika kita menjalankan ini SELECT
SELECT 'UPDATE `mydatabase`.`mytable` SET `Foo` = 0' AS sql
Itu mengembalikan kita satu baris, berisi satu kolom (kolom itu bernama sql
, tetapi nama kolom tidak penting bagi kami). Nilai kolom hanya akan berupa string. Tetapi string yang kami dapatkan kembali adalah (kami harap) pernyataan SQL yang dapat kami jalankan.
Kita akan mendapatkan hal yang sama jika kita memecah tali itu menjadi beberapa bagian, dan menggunakan CONCAT untuk mengikatnya kembali untuk kita, mis.
SELECT CONCAT('UPDATE `','mydatabase','`.`','mytable','` SET `Foo` = 0') AS sql
Kita dapat menggunakan kueri itu sebagai model untuk pernyataan yang ingin kita jalankan terhadap information_schema.columns
. Kami akan mengganti 'mydatabase'
dan 'mytable'
dengan referensi ke kolom dari information_schema.columns
tabel yang memberi kita database dan nama_tabel.
SELECT CONCAT('UPDATE `',c.table_schema,'`.`',c.table_name,'` SET `Foo` = 0') AS sql
FROM information_schema.columns
WHERE c.column_name = 'Foo'
Ada beberapa database yang pasti tidak ingin memperbarui... mysql
, information_schema
, performance_schema
. Kami juga memerlukan daftar putih database yang berisi tabel yang ingin kami perbarui
AND c.table_schema IN ('mydatabase','anotherdatabase')
-atau - kita perlu membuat daftar hitam database yang pasti tidak ingin kita perbarui
AND c.table_schema NOT IN ('mysql','information_schema','performance_schema')
Kami dapat menjalankan kueri itu (kami dapat menambahkan ORDER BY
jika kita ingin baris dikembalikan dalam urutan tertentu) dan yang kita dapatkan kembali adalah daftar yang berisi pernyataan yang ingin kita jalankan. Jika kita menyimpan kumpulan string itu sebagai file teks biasa (tidak termasuk baris header dan pemformatan tambahan), menambahkan titik koma di akhir setiap baris, kita akan memiliki file yang bisa kita jalankan dari mysql>
klien baris perintah.
(Jika salah satu di atas membingungkan, beri tahu saya.)
Bagian selanjutnya sedikit lebih rumit. Sisanya berhubungan dengan alternatif untuk menyimpan output dari SELECT sebagai file teks biasa, dan menjalankan pernyataan dari mysql
klien baris perintah.
MySQL menyediakan fasilitas/fitur yang memungkinkan kita untuk mengeksekusi pada dasarnya apa saja string sebagai pernyataan SQL, dalam konteks program tersimpan MySQL (misalnya, prosedur tersimpan. Fitur yang akan kita gunakan disebut SQL dinamis .
Untuk menggunakan SQL dinamis , kami menggunakan pernyataan PREPARE
, EXECUTE
dan DEALLOCATE PREPARE
. (Deallocate tidak sepenuhnya diperlukan, MySQL akan membersihkan untuk kita jika kita tidak menggunakannya, tapi saya pikir itu praktik yang baik untuk melakukannya.)
Sekali lagi, SQL dinamis tersedia HANYA dalam konteks program tersimpan MySQL. Untuk melakukan ini, kita perlu memiliki string yang berisi pernyataan SQL yang ingin kita jalankan. Sebagai contoh sederhana, katakanlah kita memiliki ini:
DECLARE str VARCHAR(2000);
SET str = 'UPDATE mytable SET mycol = 0 WHERE mycol < 0';
Untuk mendapatkan isi str
dievaluasi dan dieksekusi sebagai pernyataan SQL, garis besarnya adalah:
PREPARE stmt FROM str;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
Bagian rumit berikutnya adalah menyatukannya dengan kueri yang kita jalankan untuk mendapatkan nilai string yang ingin kita jalankan sebagai pernyataan SQL. Untuk melakukan itu, kami menyusun loop kursor. Garis besar dasar untuk itu adalah dengan mengambil pernyataan SELECT kami:
SELECT bah FROM humbug
Dan ubah itu menjadi definisi kursor:
DECLARE mycursor FOR SELECT bah FROM humbug ;
Yang ingin kita lakukan adalah menjalankannya dan mengulang baris yang dikembalikannya. Untuk mengeksekusi pernyataan dan menyiapkan hasil, kita "membuka" kursor
OPEN mycursor;
Ketika kami selesai dengan itu, kami akan mengeluarkan "tutup", untuk merilis hasil, sehingga server MySQL tahu kami tidak membutuhkannya lagi, dan dapat membersihkan, dan membebaskan sumber daya yang dialokasikan untuk itu.
CLOSE mycursor;
Namun, sebelum kita menutup kursor, kita ingin "mengulang" melalui hasil, mengambil setiap baris, dan melakukan sesuatu dengan baris tersebut. Pernyataan yang kita gunakan untuk mendapatkan baris berikutnya dari resultet menjadi variabel prosedur adalah:
FETCH mycursor INTO some_variable;
Sebelum kita dapat mengambil baris ke dalam variabel, kita perlu mendefinisikan variabel, mis.
DECLARE some_variable VARCHAR(2000);
Karena kursor kami (pernyataan SELECT) hanya mengembalikan satu kolom, kami hanya membutuhkan satu variabel. Jika kami memiliki lebih banyak kolom, kami membutuhkan variabel untuk setiap kolom.
Akhirnya, kita akan mengambil baris terakhir dari kumpulan hasil. Saat kami mencoba mengambil yang berikutnya, MySQL akan membuat kesalahan.
Bahasa pemrograman lain akan membiarkan kita melakukan while
loop, dan mari kita ambil baris dan keluar dari loop setelah kita memproses semuanya. MySQL lebih misterius. Untuk melakukan pengulangan:
mylabel: LOOP
-- do something
END LOOP mylabel;
Itu dengan sendirinya membuat loop tak terbatas yang sangat bagus, karena loop itu tidak memiliki "keluar". Untungnya, MySQL memberi kita LEAVE
pernyataan sebagai cara untuk keluar dari loop. Kami biasanya tidak ingin keluar dari loop saat pertama kali kami memasukinya, jadi biasanya ada beberapa tes bersyarat yang kami gunakan untuk menentukan apakah kami sudah selesai, dan harus keluar dari loop, atau kami belum selesai, dan harus berkeliling lingkaran itu lagi.
mylabel: LOOP
-- do something useful
IF some_condition THEN
LEAVE mylabel;
END IF;
END LOOP mylabel;
Dalam kasus kami, kami ingin mengulang semua baris di hasil, jadi kami akan menempatkan FETCH
a pernyataan pertama di dalam loop (sesuatu yang berguna yang ingin kita lakukan).
Untuk mendapatkan hubungan antara kesalahan yang dilontarkan MySQL saat kami mencoba mengambil melewati baris terakhir di kumpulan hasil, dan uji kondisional, kami harus menentukan apakah kami harus meninggalkan...
MySQL menyediakan cara bagi kita untuk mendefinisikan CONTINUE HANDLER
(beberapa pernyataan yang ingin kita tampilkan) ketika kesalahan dilemparkan...
DECLARE CONTINUE HANDLER FOR NOT FOUND
Tindakan yang ingin kita lakukan adalah menyetel variabel ke TRUE.
SET done = TRUE;
Sebelum kita dapat menjalankan SET, kita perlu mendefinisikan variabel:
DECLARE done TINYINT(1) DEFAULT FALSE;
Dengan itu kita, dapat mengubah LOOP kita untuk menguji apakah done
variabel disetel ke TRUE, sebagai kondisi keluar, jadi loop kita terlihat seperti ini:
mylabel: LOOP
FETCH mycursor INTO some_variable;
IF done THEN
LEAVE mylabel;
END IF;
-- do something with the row
END LOOP mylabel;
"Lakukan sesuatu dengan baris" adalah tempat kami ingin mengambil konten some_variable
dan lakukan sesuatu yang berguna dengannya. Kursor kami mengembalikan string yang ingin kami jalankan sebagai pernyataan SQL. Dan MySQL memberi kita SQL dinamis fitur yang dapat kita gunakan untuk melakukan itu.
CATATAN:MySQL memiliki aturan tentang urutan pernyataan dalam prosedur. Misalnya DECLARE
pernyataan harus datang di awal. Dan menurut saya CONTINUE HANDLER harus menjadi hal terakhir yang diumumkan.
Sekali lagi:kursor dan SQL dinamis fitur yang tersedia HANYA dalam konteks program tersimpan MySQL, seperti prosedur tersimpan. Contoh yang saya berikan di atas hanyalah contoh body dari suatu prosedur.
Untuk membuat ini dibuat sebagai prosedur tersimpan, itu perlu dimasukkan sebagai bagian dari sesuatu seperti ini:
DELIMITER $$
DROP PROCEDURE IF EXISTS myproc $$
CREATE PROCEDURE myproc
NOT DETERMINISTIC
MODIFIES SQL DATA
BEGIN
-- procedure body goes here
END$$
DELIMITER ;
Mudah-mudahan, itu menjelaskan contoh yang saya berikan sedikit lebih detail.