如果列不存在,请将列添加到mysql表中

时间:2009-06-09 22:59:35

标签: mysql

我的研究和实验还没有得出答案,所以我希望得到一些帮助。

我正在修改应用程序的安装文件,该应用程序在以前的版本中没有我想要立即添加的列。我不想手动添加列,而是在安装文件中,并且只有在表中不存在新列时才会添加。

该表创建如下:

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

有没有人有这么好的方法呢?

15 个答案:

答案 0 :(得分:80)

这是一个可行的解决方案(刚刚在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()返回名称 当前选择的数据库。

答案 1 :(得分:48)

请注意,5.0之前的MySQL不支持INFORMATION_SCHEMA。在5.0之前也不支持存储过程,所以如果你需要支持MySQL 4.1,这个解决方案就不好了。

使用数据库迁移的框架使用的一种解决方案是在数据库中记录模式的修订号。只是一个包含单列和单行的表,其中一个整数表示哪个版本是当前有效的。更新架构时,请增加数字。

另一种解决方案是尝试 ALTER TABLE ADD COLUMN命令。如果列已经存在,它应该抛出错误。

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

抓住错误并在升级脚本中忽略它。

答案 2 :(得分:32)

大多数答案都解决了如何在存储过程中安全地添加列,我需要在不使用存储过程的情况下安全地向表添加列,并发现MySQL不允许使用{{1}在 SP 之外。我会发布我的解决方案,它可能会帮助处于相同情况的人。

IF Exists()

答案 3 :(得分:31)

如果您使用MariaDB,则无需使用存储过程。只需使用,例如:

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

See here

答案 4 :(得分:22)

另一种方法是使用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

答案 5 :(得分:6)

我正在使用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;
$$

我没有编写安全修改列的过程,但我认为可以很容易地修改上述过程。

答案 6 :(得分:5)

我已经采用了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 ;

答案 7 :(得分:1)

刚试过存储过程脚本。似乎问题是分隔符周围的'标记。 MySQL Docs表示分隔符不需要单引号。

所以你想要:

delimiter //

而不是:

delimiter '//'

适合我:)

答案 8 :(得分:1)

如果您在脚本中运行此操作,则需要在之后添加以下行以使其可重新运行,否则您将获得一个过程已存在错误。

drop procedure foo;

答案 9 :(得分:1)

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

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

注意:表中的列不可重复,这意味着我们不需要检查列的存在,但为了解决问题,我们检查上面的代码:

例如,如果它工作警报1,如果不是0,这意味着该列存在! :)

答案 10 :(得分:1)

检查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 :)

答案 11 :(得分:0)

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

答案 12 :(得分:0)

以下是MySQL中的存储过程在不同数据库中的不同表中添加列(如果数据库中不存在列具有以下优点的表)

  • 可以立即添加多个列以更改不同数据库中的多个表
  • 运行三个mysql命令,即DROP,CREATE,CALL For Procedure
  • 数据库名称应根据使用情况进行更改,否则可能会出现多个数据的问题

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

答案 13 :(得分:0)

这是我的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部分。

答案 14 :(得分:-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 '';