Menggunakan ALTER untuk menghapus kolom jika ada di MySQL

92

Bagaimana ALTER dapat digunakan untuk menjatuhkan kolom di tabel MySQL jika kolom itu ada?

Saya tahu saya bisa menggunakan ALTER TABLE my_table DROP COLUMN my_column, tapi itu akan menimbulkan kesalahan jika my_columntidak ada. Apakah ada sintaks alternatif untuk menjatuhkan kolom secara kondisional?

Saya menggunakan MySQL versi 4.0.18.

jcodeninja
sumber
6
Pertanyaan ini disebutkan di Meta .
Hanya pelajar

Jawaban:

70

Untuk MySQL, tidak ada: Permintaan Fitur MySQL .

Membiarkan ini bisa dibilang ide yang sangat buruk, bagaimanapun: IF EXISTSmenunjukkan bahwa Anda menjalankan operasi destruktif pada database dengan (kepada Anda) struktur yang tidak diketahui. Mungkin ada situasi di mana ini dapat diterima untuk pekerjaan lokal yang cepat dan kotor, tetapi jika Anda tergoda untuk menjalankan pernyataan seperti itu terhadap data produksi (dalam migrasi dll.), Anda bermain-main dengan api.

Tetapi jika Anda bersikeras, tidak sulit untuk hanya memeriksa keberadaannya terlebih dahulu di klien, atau untuk menemukan kesalahannya.

MariaDB juga mendukung yang berikut, dimulai dengan 10.0.2:

DROP [COLUMN] [IF EXISTS] col_name 

yaitu

ALTER TABLE my_table DROP IF EXISTS my_column;

Tapi bisa dibilang ide yang buruk untuk mengandalkan fitur non-standar yang hanya didukung oleh satu dari beberapa fork MySQL.

Matthias Winkelmann
sumber
8
Apakah ada cara untuk melakukannya dalam SQL murni?
Tom
16
Wow. Disebutkan pada tahun 2005 - 9 tahun yang lalu. Saya rasa ini ada di bawah daftar prioritas ...
crmpicco
4
MariaDB mendukungnya mulai dari 10.0.2
Dfr
17
"Membiarkan ini bisa dibilang ide yang sangat buruk," - Saya tidak setuju. Mengapa seseorang harus membuat asumsi tentang kasus penggunaan pengguna? Saya memiliki banyak database dan saya perlu menyelaraskannya. Sungguh menyebalkan ketika perangkat lunak ingin lebih pintar dari manusia ...
Onkeltem
5
14 tahun berlalu, masih belum sampai. Saya tidak berpikir ini akan pernah selesai.
Steve Horvath
45

Tidak ada dukungan tingkat bahasa untuk ini di MySQL. Berikut adalah solusi yang melibatkan meta-data MySQL information_schema di 5.0+, tetapi itu tidak akan mengatasi masalah Anda di 4.0.18.

drop procedure if exists schema_change;

delimiter ';;'
create procedure schema_change() begin

    /* delete columns if they exist */
    if exists (select * from information_schema.columns where table_schema = schema() and table_name = 'table1' and column_name = 'column1') then
        alter table table1 drop column `column1`;
    end if;
    if exists (select * from information_schema.columns where table_schema = schema() and table_name = 'table1' and column_name = 'column2') then
        alter table table1 drop column `column2`;
    end if;

    /* add columns */
    alter table table1 add column `column1` varchar(255) NULL;
    alter table table1 add column `column2` varchar(255) NULL;

end;;

delimiter ';'
call schema_change();

drop procedure if exists schema_change;

Saya menulis beberapa informasi yang lebih rinci dalam posting blog .

Chase Seibert
sumber
3
Saya pikir penting untuk meringkas kontribusi DrHyde sebagai komentar, karena tidak terlihat ketika dalam jawaban itu sendiri. Pastikan Anda memeriksa bahwa Anda tidak mengubah database yang berbeda: SELECT * from information_schema.columns WHERE table_name = "country" AND column_name = "updated_at" AND table_schema = DATABASE () \ G
Homer6
Jika Anda tidak ingin mendapatkan peringatan dari "prosedur drop jika ada schema_change;" tambahkan "set sql_notes = 0;" sebelum baris pertama dan tambahkan "set sql_notes = 1;" setelah baris terakhir. Detail -> stackoverflow.com/questions/27616564/suppress-mysql-warnings
csonuryilmaz
"pembatas" harus tanpa '' (misalnya -> pembatas ;;)
Illidan
17

Saya tahu ini adalah utas lama, tetapi ada cara sederhana untuk menangani persyaratan ini tanpa menggunakan prosedur tersimpan. Ini dapat membantu seseorang.

set @exist_Check := (
    select count(*) from information_schema.columns 
    where TABLE_NAME='YOUR_TABLE' 
    and COLUMN_NAME='YOUR_COLUMN' 
    and TABLE_SCHEMA=database()
) ;
set @sqlstmt := if(@exist_Check>0,'alter table YOUR_TABLE drop column YOUR_COLUMN', 'select ''''') ;
prepare stmt from @sqlstmt ;
execute stmt ;

Semoga ini membantu seseorang, seperti yang saya lakukan (setelah banyak trial and error).

Pradeep Puranik
sumber
Itu pasti berhasil. Terima kasih @Pradeep
Sumit Deshmukh
14

Saya baru saja membuat prosedur yang dapat digunakan kembali yang dapat membantu membuat DROP COLUMNidempoten:

-- column_exists:

DROP FUNCTION IF EXISTS column_exists;

DELIMITER $$
CREATE FUNCTION column_exists(
  tname VARCHAR(64),
  cname VARCHAR(64)
)
  RETURNS BOOLEAN
  READS SQL DATA
  BEGIN
    RETURN 0 < (SELECT COUNT(*)
                FROM `INFORMATION_SCHEMA`.`COLUMNS`
                WHERE `TABLE_SCHEMA` = SCHEMA()
                      AND `TABLE_NAME` = tname
                      AND `COLUMN_NAME` = cname);
  END $$
DELIMITER ;

-- drop_column_if_exists:

DROP PROCEDURE IF EXISTS drop_column_if_exists;

DELIMITER $$
CREATE PROCEDURE drop_column_if_exists(
  tname VARCHAR(64),
  cname VARCHAR(64)
)
  BEGIN
    IF column_exists(tname, cname)
    THEN
      SET @drop_column_if_exists = CONCAT('ALTER TABLE `', tname, '` DROP COLUMN `', cname, '`');
      PREPARE drop_query FROM @drop_column_if_exists;
      EXECUTE drop_query;
    END IF;
  END $$
DELIMITER ;

Pemakaian:

CALL drop_column_if_exists('my_table', 'my_column');

Contoh:

SELECT column_exists('my_table', 'my_column');       -- 1
CALL drop_column_if_exists('my_table', 'my_column'); -- success
SELECT column_exists('my_table', 'my_column');       -- 0
CALL drop_column_if_exists('my_table', 'my_column'); -- success
SELECT column_exists('my_table', 'my_column');       -- 0
sp00m
sumber
5

Jawaban Chase Seibert berfungsi, tetapi saya akan menambahkan bahwa jika Anda memiliki beberapa skema, Anda ingin mengubah SELECT sebagai:

select * from information_schema.columns where table_schema in (select schema()) and table_name=...
DrHyde
sumber
1

Mungkin cara paling sederhana untuk menyelesaikan ini (yang akan berhasil) adalah:

  • BUAT tabel_baru SEBAGAI PILIH id, col1, col2, ... (hanya kolom yang benar-benar Anda inginkan di tabel akhir) DARI tabel_saya;

  • GANTI NAMA tabel_saya KE tabel_ lama, tabel_baru KE tabel_saya;

  • DROP old_table;

Atau pertahankan old_table untuk rollback jika perlu.

Ini akan berfungsi tetapi kunci asing tidak akan dipindahkan. Anda harus menambahkannya kembali ke my_table nanti; juga kunci asing di tabel lain yang mereferensikan my_table harus diperbaiki (menunjuk ke my_table baru).

Semoga berhasil...

Frank Flynn
sumber
1

Anda dapat menggunakan skrip ini, menggunakan kolom, skema dan nama tabel Anda

 IF EXISTS (SELECT *
                         FROM INFORMATION_SCHEMA.COLUMNS
                         WHERE TABLE_NAME = 'TableName' AND COLUMN_NAME = 'ColumnName' 
                                             AND TABLE_SCHEMA = SchemaName)
    BEGIN
       ALTER TABLE TableName DROP COLUMN ColumnName;
    END;
Shah Zaiƞ
sumber
-3

Saya menyadari utas ini sudah cukup tua sekarang, tetapi saya mengalami masalah yang sama. Ini adalah solusi paling dasar saya menggunakan MySQL Workbench, tetapi berfungsi dengan baik ...

  1. dapatkan editor sql baru dan jalankan SHOW TABLES untuk mendapatkan daftar tabel Anda
  2. pilih semua baris, dan pilih salin ke papan klip (tidak dikutip) dari menu konteks
  3. tempelkan daftar nama ke tab editor lain
  4. tulis permintaan Anda, yaitu ALTER TABLE xDROP a;
  5. lakukan beberapa salin dan tempel, sehingga Anda berakhir dengan kueri terpisah untuk setiap tabel
  6. Beralih apakah meja kerja harus berhenti saat terjadi kesalahan
  7. Tekan jalankan dan lihat log keluaran

setiap tabel yang memiliki tabel sekarang tidak memiliki tabel yang tidak akan menampilkan kesalahan di log

maka Anda dapat menemukan / mengganti 'drop a' mengubahnya menjadi 'ADD COLUMN bINT NULL' dll dan jalankan semuanya lagi ....

agak kikuk, tetapi akhirnya Anda mendapatkan hasil akhirnya dan Anda dapat mengontrol / memantau seluruh proses dan ingat untuk menyimpan skrip sql jika Anda membutuhkannya lagi.

ajp
sumber