Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Cara memilih semua tabel dengan nama kolom dan memperbarui kolom itu

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.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. hitungan lambat (*) di innoDB

  2. Pencarian lambat dengan kueri indeks LIKE% MYSQL

  3. Bagaimana menjaga koneksi tetap hidup di java

  4. Urutan Lon/Lat saat menggunakan tipe POINT spasial dengan MySQL

  5. Bagaimana cara menambahkan bobot ke tabel MySQL dan memilih nilai acak menurut ini?