tambahkan kolom ke tabel mysql jika tidak ada

109

Penelitian dan eksperimen saya belum membuahkan jawaban, jadi saya mengharapkan bantuan.

Saya memodifikasi file instal aplikasi yang di versi sebelumnya tidak memiliki kolom yang ingin saya tambahkan sekarang. Saya tidak ingin menambahkan kolom secara manual, tetapi di file instalasi dan hanya jika kolom baru belum ada di tabel.

Tabel dibuat sebagai berikut:

CREATE TABLE IF NOT EXISTS `#__comm_subscribers` (
      `subscriber_id` int(11) NOT NULL auto_increment,
      `user_id` int(11) NOT NULL default '0',
      `subscriber_name` varchar(64) NOT NULL default '',
      `subscriber_surname` varchar(64) NOT NULL default '',
      `subscriber_email` varchar(64) NOT NULL default '',
      `confirmed` tinyint(1) NOT NULL default '0',
      `subscribe_date` datetime NOT NULL default '0000-00-00 00:00:00',
      PRIMARY KEY  (`subscriber_id`),
      UNIQUE KEY `subscriber_email` (`subscriber_email`)
    ) ENGINE=MyISAM CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' COMMENT='Subscribers for Comm are stored here.';

Jika saya menambahkan yang berikut ini, di bawah pernyataan buat tabel, maka saya tidak yakin apa yang terjadi jika kolom tersebut sudah ada (dan mungkin terisi):

ALTER TABLE `#__comm_subscribers` ADD `subscriber_surname`;
ALTER TABLE `#__comm_subscribers` MODIFY `subscriber_surname` varchar(64) NOT NULL default '';

Jadi, saya mencoba yang berikut yang saya temukan di suatu tempat. Ini sepertinya tidak berhasil tetapi saya tidak sepenuhnya yakin saya menggunakannya dengan benar.

/*delimiter '//'
CREATE PROCEDURE addcol() BEGIN
IF NOT EXISTS(
SELECT * FROM information_schema.COLUMNS
WHERE COLUMN_NAME='subscriber_surname' AND TABLE_NAME='#__comm_subscribers'
)
THEN
    ALTER TABLE `#__comm_subscribers`
    ADD COLUMN `subscriber_surname` varchar(64) NOT NULL default '';
END IF;
END;
//
delimiter ';'
CALL addcol();
DROP PROCEDURE addcol;*/

Adakah yang punya cara yang baik untuk melakukan ini?

E Wierda
sumber
2
Mengubah information_schema.COLUMNS, yaitu apa yang dilakukan prosedur tersimpan, adalah cara untuk menggunakan IMHO. Bagian mana yang "sepertinya tidak berhasil"?
rodion

Jawaban:

49

Perhatikan bahwa INFORMATION_SCHEMAtidak didukung di MySQL sebelum 5.0. Prosedur tersimpan juga tidak didukung sebelum 5.0, jadi jika Anda perlu mendukung MySQL 4.1, solusi ini tidak baik.

Salah satu solusi yang digunakan oleh framework yang menggunakan migrasi database adalah mencatat dalam database Anda nomor revisi untuk skema. Hanya tabel dengan satu kolom dan satu baris, dengan bilangan bulat yang menunjukkan revisi mana yang sedang berlaku. Saat Anda memperbarui skema, tambahkan angkanya.

Solusi lain akan hanya mencoba yang ALTER TABLE ADD COLUMNperintah. Ini harus memunculkan kesalahan jika kolom sudah ada.

ERROR 1060 (42S21): Duplicate column name 'newcolumnname'

Tangkap kesalahan dan abaikan dalam skrip peningkatan Anda.

Bill Karwin
sumber
1
Oke, ini benar-benar kasar, tetapi seseorang harus mengatakannya. jika Anda hanya menjalankan skrip SQL dari baris perintah, Anda dapat memberi mysql --forcesakelar, yang berarti terus berjalan meskipun ada kesalahan. lalu, lakukan saja. Anda hanya ingin memastikan bahwa tidak ada pernyataan yang TIDAK Anda inginkan untuk berhasil jika sesuatu yang sebelumnya gagal.
David
85

Berikut adalah solusi yang berfungsi (baru saja mencoba dengan MySQL 5.0 di Solaris):

DELIMITER $$

DROP PROCEDURE IF EXISTS upgrade_database_1_0_to_2_0 $$
CREATE PROCEDURE upgrade_database_1_0_to_2_0()
BEGIN

-- rename a table safely
IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()
        AND TABLE_NAME='my_old_table_name') ) THEN
    RENAME TABLE 
        my_old_table_name TO my_new_table_name,
END IF;

-- add a column safely
IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()
        AND COLUMN_NAME='my_additional_column' AND TABLE_NAME='my_table_name') ) THEN
    ALTER TABLE my_table_name ADD my_additional_column varchar(2048) NOT NULL DEFAULT '';
END IF;

END $$

CALL upgrade_database_1_0_to_2_0() $$

DELIMITER ;

Sekilas mungkin terlihat lebih rumit dari yang seharusnya, tetapi kita harus mengatasi masalah berikut di sini:

  • IF pernyataan hanya bekerja dalam prosedur yang tersimpan, tidak ketika dijalankan secara langsung, misalnya di klien mysql
  • lebih elegan dan ringkas SHOW COLUMNStidak berfungsi dalam prosedur tersimpan jadi harus menggunakan INFORMATION_SCHEMA
  • sintaks untuk pernyataan pembatas aneh di MySQL, jadi Anda harus mendefinisikan ulang pembatas untuk dapat membuat prosedur yang tersimpan. Jangan lupa untuk mengganti pembatas kembali!
  • INFORMATION_SCHEMA bersifat global untuk semua database, jangan lupa untuk memfilter TABLE_SCHEMA=DATABASE(). DATABASE()mengembalikan nama database yang saat ini dipilih.
geekQ
sumber
1
Seandainya saya dapat memberikan poin bonus untuk menjelaskan masalah yang terlibat yang menyebabkan pendekatan ini. Terima kasih.
Bryan Petty
48

Jika Anda menggunakan MariaDB, tidak perlu menggunakan prosedur tersimpan. Gunakan saja, misalnya:

ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name tinyint(1) DEFAULT 0;

Lihat disini

giuseppe
sumber
8
Cemerlang! Namun alasan lain untuk menggunakan MariaDB.
Andrew Ensley
+1 Saya telah bekerja dengan Maria sepanjang waktu dan mencoba semua langkah di atas tidak satupun yang berhasil sampai saya mendapatkan yang ini, ini menyelamatkan hidup saya.
Thielicious
Menarik .. Saya tidak pernah keras tentang MariaDB dan artikel ini dapat memberikan gambaran tentangnya seravo.fi/2015/…
walv
Solusi ini bagus, tetapi membutuhkan MariaDB 10.0.2. Hanya pendahuluan untuk siapa saja yang ingin menggunakan solusi elegan ini, tetapi terjebak pada versi yang lebih lama.
jblopez
ALTER TABLE table_name CHANGE COLUMN IF EXISTS column_wrong_name column_name tinyint (1) DEFAULT 0; -Bekerja juga bagus!
Damonsson
34

Sebagian besar jawaban membahas cara menambahkan kolom dengan aman dalam prosedur yang tersimpan, saya harus menambahkan kolom ke tabel dengan aman tanpa menggunakan proc yang disimpan dan menemukan bahwa MySQL tidak mengizinkan penggunaan IF Exists()luar SP . Saya akan memposting solusi saya yang mungkin membantu seseorang dalam situasi yang sama.

SELECT count(*)
INTO @exist
FROM information_schema.columns 
WHERE table_schema = database()
and COLUMN_NAME = 'original_data'
AND table_name = 'mytable';

set @query = IF(@exist <= 0, 'alter table intent add column mycolumn4 varchar(2048) NULL after mycolumn3', 
'select \'Column Exists\' status');

prepare stmt from @query;

EXECUTE stmt;
rahvin_t
sumber
1
Catatan Saya harus menambahkan "LIMIT 1" ke pernyataan SELECT saat bekerja melalui GUI meja kerja MySQL.
Al Dass
23

Cara lain untuk melakukannya adalah dengan mengabaikan kesalahan dengan declare continue handler:

delimiter ;;
create procedure foo ()
begin
    declare continue handler for 1060 begin end;
    alter table atable add subscriber_surname varchar(64);
end;;
call foo();;

Saya pikir cara ini lebih rapi daripada dengan existssubquery. Terutama jika Anda memiliki banyak kolom untuk ditambahkan, dan Anda ingin menjalankan skrip beberapa kali.

info lebih lanjut tentang penangan lanjut dapat ditemukan di http://dev.mysql.com/doc/refman/5.0/en/declare-handler.html

Jake
sumber
Suka! Tidak akan pernah memikirkan itu. Saya pasti akan beralih ke cara melakukan sesuatu ini.
Johnny Kauffman
ERROR 1060 (42S21): Nama kolom duplikat 'newcolumnname'
Jake
Ini benar-benar bagus!
ATOzTOA
6

Saya menggunakan MySQL 5.5.19.

Saya suka memiliki skrip yang dapat Anda jalankan dan jalankan kembali tanpa kesalahan, terutama di mana peringatan tampaknya tetap ada, muncul lagi nanti saat saya menjalankan skrip yang tidak memiliki kesalahan / peringatan. Sejauh menambahkan bidang, saya menulis sendiri prosedur untuk membuatnya sedikit lebih sedikit mengetik:

-- add fields to template table to support ignoring extra data 
-- at the top/bottom of every page
CALL addFieldIfNotExists ('template', 'firstPageHeaderEndY', 'INT NOT NULL DEFAULT 0');
CALL addFieldIfNotExists ('template', 'pageHeaderEndY', 'INT NOT NULL DEFAULT 0');
CALL addFieldIfNotExists ('template', 'pageFooterBeginY', 'INT NOT NULL DEFAULT 792');

Kode untuk membuat prosedur addFieldIfNotExists adalah sebagai berikut:

DELIMITER $$

DROP PROCEDURE IF EXISTS addFieldIfNotExists 
$$

DROP FUNCTION IF EXISTS isFieldExisting 
$$

CREATE FUNCTION isFieldExisting (table_name_IN VARCHAR(100), field_name_IN VARCHAR(100)) 
RETURNS INT
RETURN (
    SELECT COUNT(COLUMN_NAME) 
    FROM INFORMATION_SCHEMA.columns 
    WHERE TABLE_SCHEMA = DATABASE() 
    AND TABLE_NAME = table_name_IN 
    AND COLUMN_NAME = field_name_IN
)
$$

CREATE PROCEDURE addFieldIfNotExists (
    IN table_name_IN VARCHAR(100)
    , IN field_name_IN VARCHAR(100)
    , IN field_definition_IN VARCHAR(100)
)
BEGIN

    -- http://javajon.blogspot.com/2012/10/mysql-alter-table-add-column-if-not.html

    SET @isFieldThere = isFieldExisting(table_name_IN, field_name_IN);
    IF (@isFieldThere = 0) THEN

        SET @ddl = CONCAT('ALTER TABLE ', table_name_IN);
        SET @ddl = CONCAT(@ddl, ' ', 'ADD COLUMN') ;
        SET @ddl = CONCAT(@ddl, ' ', field_name_IN);
        SET @ddl = CONCAT(@ddl, ' ', field_definition_IN);

        PREPARE stmt FROM @ddl;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;

    END IF;

END;
$$

Saya tidak menulis prosedur untuk mengubah kolom dengan aman, tapi menurut saya prosedur di atas dapat dengan mudah dimodifikasi untuk melakukannya.

Jonathan
sumber
5

Saya telah mengambil sproc OP dan membuatnya dapat digunakan kembali dan skema independen. Jelas masih membutuhkan MySQL 5.

DROP PROCEDURE IF EXISTS AddCol;

DELIMITER //

CREATE PROCEDURE AddCol(
    IN param_schema VARCHAR(100),
    IN param_table_name VARCHAR(100),
    IN param_column VARCHAR(100),
    IN param_column_details VARCHAR(100)
) 
BEGIN
    IF NOT EXISTS(
    SELECT NULL FROM information_schema.COLUMNS
    WHERE COLUMN_NAME=param_column AND TABLE_NAME=param_table_name AND table_schema = param_schema
    )
    THEN
        set @paramTable = param_table_name ;
        set @ParamColumn = param_column ;
        set @ParamSchema = param_schema;
        set @ParamColumnDetails = param_column_details;
        /* Create the full statement to execute */
        set @StatementToExecute = concat('ALTER TABLE `',@ParamSchema,'`.`',@paramTable,'` ADD COLUMN `',@ParamColumn,'` ',@ParamColumnDetails);
        /* Prepare and execute the statement that was built */
        prepare DynamicStatement from @StatementToExecute ;
        execute DynamicStatement ;
        /* Cleanup the prepared statement */
        deallocate prepare DynamicStatement ;

    END IF;
END //

DELIMITER ;
Thomas Paine
sumber
Ini bekerja dengan baik untuk saya. Satu-satunya perubahan yang harus saya lakukan adalah menghapus tanda kutip belakang (`) dalam panggilan untuk concat. Selain itu, dapat menyederhanakan kode dengan menghapus variabel @paramTable, @ParamColumn, @ParamSchema, dan @ParamColumnDetails dan langsung menggunakan parameternya.
hrabinowitz
1

Baru saja mencoba skrip prosedur tersimpan. Sepertinya masalahnya adalah 'tanda di sekitar pembatas. The MySQL Docs menunjukkan bahwa karakter pembatas tidak perlu tanda kutip tunggal.

Jadi Anda ingin:

delimiter //

Dari pada:

delimiter '//'

Bekerja untuk saya :)

Boy Who Roared
sumber
@Anda benar-benar melewatkan intinya. Komentar ini menunjukkan di mana OP melakukan kesalahannya. OP sudah ada jika bukan karena tanda kutip tunggal.
RichardTheKiwi
1

Jika Anda menjalankan ini dalam skrip, Anda akan ingin menambahkan baris berikut setelah itu untuk membuatnya dapat dibuka kembali, jika tidak Anda mendapatkan kesalahan prosedur sudah ada.

drop procedure foo;
pembuat tikar
sumber
1

Cara terbaik untuk menambahkan kolom di PHP> PDO:

$Add = $dbh->prepare("ALTER TABLE `YourCurrentTable` ADD `YourNewColumnName` INT NOT NULL");
$Add->execute();

Catatan: kolom pada tabel tidak dapat diulang, artinya kita tidak perlu memeriksa keberadaan kolom, tetapi untuk menyelesaikan masalah kita periksa kode di atas:

misalnya jika berfungsi alert 1, jika bukan 0, artinya kolom tersebut ada! :)

Maher
sumber
1

Periksa apakah Kolom Ada atau tidak di PDO (100%)

{
    if(isset($_POST['Add']))
    {
        $ColumnExist = $dbh->prepare("SELECT * FROM ColumnChecker where column_name='$insert_column_name' LIMIT 1");
        $ColumnExist ->execute();
        $ColumnName = $ColumnExist->fetch(2);
        $Display_Column_Name = $ColumnName['column_name'];

        if($Display_Column_Name == $insert_column_name)
        {
            echo "$Display_Column_Name already exist";
        } //*****************************
        else 
        {
            $InsertColumn = $dbh->prepare("insert into ColumnChecker ( column_name ) values ('$insert_column_name')");
            $InsertColumn->execute();

            if($InsertColumn)
            {
                $Add = $dbh->prepare("ALTER TABLE `$Table` ADD `$insert_column_name` $insert_column_type($insert_column_Length) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ");
                $Add->execute();

                if($Add)
                {
                    echo 'Table has been updated';  
                }
                else 
                {
                    echo 'Sorry! Try again...'; 
                }
            }   
        }
    }
}#Add Column into Table :)
Maher
sumber
1

Prosedur dari Jake https://stackoverflow.com/a/6476091/6751901 adalah solusi yang sangat sederhana dan bagus untuk menambahkan kolom baru, tetapi dengan satu baris tambahan:

DROP PROCEDURE IF EXISTS foo;;

Anda dapat menambahkan kolom baru nanti di sana, dan ini akan berfungsi di lain waktu:

delimiter ;;
DROP PROCEDURE IF EXISTS foo;;
create procedure foo ()
begin
    declare continue handler for 1060 begin end;
    alter table atable add subscriber_surname varchar(64);
    alter table atable add subscriber_address varchar(254);
end;;
call foo();;
simpel
sumber
0
$smpt = $pdo->prepare("SHOW fields FROM __TABLE__NAME__");
$smpt->execute();
$res = $smpt->fetchAll(PDO::FETCH_ASSOC);
//print_r($res);

Kemudian di $ res by cycle cari kunci kolom anda Smth seperti ini:

    if($field['Field'] == '_my_col_'){
       return true;
    }
+

**Below code is good for checking column existing in the WordPress tables:**
public static function is_table_col_exists($table, $col)
    {
        global $wpdb;
        $fields = $wpdb->get_results("SHOW fields FROM {$table}", ARRAY_A);
        foreach ($fields as $field)
        {
            if ($field['Field'] == $col)
            {
                return TRUE;
            }
        }

        return FALSE;
    }
realmag777
sumber
1
ini dapat dilakukan sedikit lebih efisien SHOW fields FROM __TABLE__NAME__ where field='_my_col_'; dan kemudian memeriksa hasil yang ditetapkan tidak kosong
Eugen Mayer
0

Di bawah ini adalah prosedur Tersimpan di MySQL Untuk Menambahkan Kolom di Tabel yang berbeda di Database yang berbeda jika kolom tidak ada di Tabel Database dengan keuntungan sebagai berikut

  • beberapa kolom dapat ditambahkan sekaligus untuk mengubah beberapa Tabel di berbagai Database
  • tiga perintah mysql dijalankan, yaitu DROP, CREATE, CALL For Procedure
  • Nama DATABASE harus diubah sesuai PENGGUNAAN jika tidak masalah dapat terjadi untuk beberapa data

DROP PROCEDURE  IF EXISTS `AlterTables`;
DELIMITER $$
CREATE PROCEDURE `AlterTables`() 
BEGIN
    DECLARE table1_column1_count INT;
    DECLARE table2_column2_count INT;
    SET table1_column1_count = (  SELECT COUNT(*) 
                    FROM INFORMATION_SCHEMA.COLUMNS
                    WHERE   TABLE_SCHEMA = 'DATABASE_NAME' AND
			    TABLE_NAME = 'TABLE_NAME1' AND 
                            COLUMN_NAME = 'TABLE_NAME1_COLUMN1');
    SET table2_column2_count = (  SELECT COUNT(*) 
                    FROM INFORMATION_SCHEMA.COLUMNS
                    WHERE   TABLE_SCHEMA = 'DATABASE_NAME' AND
			    TABLE_NAME = 'TABLE_NAME2' AND 
                            COLUMN_NAME = 'TABLE_NAME2_COLUMN2');
    IF table1_column1_count = 0 THEN
        ALTER TABLE `TABLE_NAME1`ADD `TABLE_NAME1_COLUMN1` text COLLATE 'latin1_swedish_ci' NULL AFTER `TABLE_NAME1_COLUMN3`,COMMENT='COMMENT HERE';
    END IF;
    IF table2_column2_count = 0 THEN
        ALTER TABLE `TABLE_NAME2` ADD `TABLE_NAME2_COLUMN2` VARCHAR( 100 ) NULL DEFAULT NULL COMMENT 'COMMENT HERE';
    END IF;
END $$
DELIMITER ;
call AlterTables();

Abdul Rehman
sumber
-1
ALTER TABLE `subscriber_surname` ADD  IF NOT EXISTS  `#__comm_subscribers`.`subscriber_surname`;

ALTER TABLE `#__comm_subscribers` MODIFY `subscriber_surname` varchar(64) NOT NULL default '';
Phạm Trần Phú Quốc
sumber
4
Akan sangat bagus jika Anda dapat menambahkan beberapa deskripsi ke solusi Anda se kita (pengguna) dapat memahami keuntungan dari solusi ini terlepas dari yang lain. Ini adalah perbaikan untuk jawaban ini dan yang akan datang.
Luís Cruz