簡體   English   中英

如果不存在,則將列添加到 mysql 表

[英]add column to mysql table if it does not exist

我的研究和實驗還沒有得到答案,所以我希望得到一些幫助。

我正在修改一個應用程序的安裝文件,該文件在以前的版本中沒有我現在要添加的列。 我不想手動添加列,而是在安裝文件中並且僅當表中不存在新列時。

該表的創建方式如下:

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.';

如果我在 create table 語句下方添加以下內容,那么我不確定如果該列已經存在(並且可能已填充)會發生什么:

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

所以,我嘗試了我在某處找到的以下內容。 這似乎不起作用,但我不完全確定我是否正確使用它。

/*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;*/

有沒有人有這樣做的好方法?

這是一個可行的解決方案(剛剛在 Solaris 上使用 MySQL 5.0 進行了嘗試):

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 ;

乍一看,它可能看起來比它應該的要復雜,但我們必須在這里處理以下問題:

  • IF語句只適用於存儲過程,而不適用於直接運行,例如在 mysql 客戶端
  • 更優雅簡潔的SHOW COLUMNS在存儲過程中不起作用所以必須使用 INFORMATION_SCHEMA
  • MySQL 中分隔語句的語法很奇怪,因此您必須重新定義分隔符才能創建存儲過程。 不要忘記將分隔符切換回來!
  • INFORMATION_SCHEMA 對所有數據庫都是全局的,不要忘記過濾TABLE_SCHEMA=DATABASE() DATABASE()返回當前選定數據庫的名稱。

如果您使用的是 MariaDB,則無需使用存儲過程。 只需使用,例如:

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

看這里

請注意,5.0 之前的 MySQL 不支持INFORMATION_SCHEMA 5.0 之前也不支持存儲過程,所以如果你需要支持 MySQL 4.1,這個解決方案並不好。

使用數據庫遷移的框架使用的一種解決方案是在數據庫中記錄模式的修訂號。 只是一個單列單行的表格,用一個整數表示當前有效的修訂版本。 更新架構時,請增加數字。

另一種解決方案是嘗試ALTER TABLE ADD COLUMN命令。 如果列已經存在,它應該拋出一個錯誤。

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

捕獲錯誤並在升級腳本中忽略它。

大多數答案都解決了如何在存儲過程中安全地添加列,我需要在不使用存儲過程的情況下安全地將列添加到表中,並發現 MySQL 不允許在SP之外使用IF Exists() . 我會發布我的解決方案,它可能會幫助處於相同情況的人。

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;

另一種方法是使用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();;

我認為這種方式比使用exists子查詢更簡潔。 特別是如果您有很多列要添加,並且您想多次運行腳本。

有關繼續處理程序的更多信息,請訪問http://dev.mysql.com/doc/refman/5.0/en/declare-handler.html

我正在使用 MySQL 5.5.19。

我喜歡有腳本,您可以無錯誤地運行和重新運行,尤其是在警告似乎持續存在的情況下,稍后在我運行沒有錯誤/警告的腳本時再次出現。 就添加字段而言,我為自己編寫了一個程序以減少輸入:

-- 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');

創建addFieldIfNotExists過程的代碼如下:

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;
$$

我沒有編寫程序來安全地修改列,但我認為可以很容易地修改上述程序來這樣做。

我采用了 OP 的 sproc 並使其可重用且與模式無關。 顯然它仍然需要 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 ;

在 PHP > PDO 中添加列的最佳方法:

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

注意:表中的列是不可重復的,也就是說我們不需要檢查列是否存在,但是為了解決問題我們檢查上面的代碼:

例如,如果它工作警報 1,如果不是 0,這意味着該列存在! :)

檢查列是否存在於 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 :)

剛剛嘗試了存儲過程腳本。 似乎問題在於分隔符周圍的'標記。 MySQL Docs顯示分隔符不需要單引號。

所以你要:

delimiter //

代替:

delimiter '//'

對我有用:)

來自 Jake https://stackoverflow.com/a/6476091/6751901 的過程是添加新列的非常簡單且很好的解決方案,但增加了一行:

DROP PROCEDURE IF EXISTS foo;;

您可以稍后在那里添加新列,下次也可以使用:

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();;

如果您在腳本中運行它,您需要在之后添加以下行以使其可重新運行,否則您會收到一個過程已經存在的錯誤。

drop procedure foo;
$smpt = $pdo->prepare("SHOW fields FROM __TABLE__NAME__");
$smpt->execute();
$res = $smpt->fetchAll(PDO::FETCH_ASSOC);
//print_r($res);

然后在 $res 中按周期查找 Smth 列的鍵,如下所示:

    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;
    }

以下是 MySQL 中的存儲過程,如果數據庫表中不存在列,則在不同數據庫中的不同表中添加列,具有以下優點

  • 可以一次添加多個列來改變不同數據庫中的多個表
  • 運行三個mysql命令,即DROP、CREATE、CALL For Procedure
  • DATABASE Name 應根據 USE 更改,否則多個數據可能會出現問題

 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();

這是我的 PHP/PDO 解決方案:

function addColumnIfNotExists($db, $table, $col, $type, $null = true) {
    global $pdo;
    if($res = $pdo->query("SHOW COLUMNS FROM `$db`.`$table` WHERE `Field`='$col'")) {
        if(!$res = $res->fetchAll(PDO::FETCH_ASSOC)) {
            $null = ($null ? 'NULL' : 'NOT NULL');
            $pdo->query("ALTER TABLE `$db`.`$table` ADD `$col` $type $null");
        }
    }
}

請注意,它會自動將列添加到表的末尾。 我還沒有實現查詢的DEFAULT部分。

ALTER TABLE `subscriber_surname` ADD  IF NOT EXISTS  `#__comm_subscribers`.`subscriber_surname`;

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM