我的研究和实验还没有得出答案,所以我希望能得到一些帮助。
我正在修改以前版本中没有我现在要添加的列的应用程序的安装文件。我不想手动添加该列,而是在安装文件中并且仅当表中不存在新列时。
创建表如下:
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,这个解决方案并不好。
使用数据库迁移的框架使用的一种解决方案是在数据库中记录模式的修订号。只是一个单列单行的表,其中有一个整数表示哪个版本是当前有效的。更新架构时,增加数字。
另一种解决方案是try ALTER TABLE ADD COLUMN
命令。如果该列已经存在,它应该抛出一个错误。
ERROR 1060 (42S21): Duplicate column name 'newcolumnname'
在升级脚本中捕获错误并忽略它。
--force
开关,这意味着即使出现错误也继续运行。那么,就去做吧。如果之前的事情失败了,你只想确保没有你不想成功的语句。
大多数答案都解决了如何在存储过程中安全地添加列,我需要在不使用存储过程的情况下安全地将列添加到表中,并发现 MySQL 不允许在 IF Exists() >SP。我会发布我的解决方案,它可能会帮助处于相同情况的人。
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;
DEALLOCATE PREPARE 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 ;
刚刚尝试了存储过程脚本。似乎问题在于分隔符周围的 '
标记。 MySQL Docs 表明分隔符不需要单引号。
所以你要:
delimiter //
代替:
delimiter '//'
为我工作:)
如果您在脚本中运行它,您需要在之后添加以下行以使其可重新运行,否则您会收到一个过程已存在错误。
drop procedure foo;
在 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 :)
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();;
$smpt = $pdo->prepare("SHOW fields FROM __TABLE__NAME__");
$smpt->execute();
$res = $smpt->fetchAll(PDO::FETCH_ASSOC);
//print_r($res);
然后在 $res by cycle 中查找列 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;
}
SHOW fields FROM __TABLE__NAME__ where field='_my_col_';
,然后检查结果集是否为非空
以下是 MySQL 中的存储过程,如果数据库表中不存在列,则在不同数据库中的不同表中添加列,具有以下优点
可以添加多个列一次使用以更改不同数据库中的多个表
三个mysql命令运行,即DROP、CREATE、CALL For Procedure
数据库名称应根据 USE 进行更改,否则可能会出现多个数据的问题
如果存在“AlterTables”,则删除程序; DELIMITER $$ CREATE PROCEDURE `AlterTables`() BEGIN DECLARE table1_column1_count INT;声明 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';万一; IF table2_column2_count = 0 THEN ALTER TABLE `TABLE_NAME2` ADD `TABLE_NAME2_COLUMN2` VARCHAR( 100 ) NULL DEFAULT NULL COMMENT 'COMMENT HERE';万一;结束 $$ 分隔符;调用 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");
}
}
}
请注意,它会自动在表格末尾添加列。我还没有实现查询的默认部分。
ALTER TABLE `subscriber_surname` ADD IF NOT EXISTS `#__comm_subscribers`.`subscriber_surname`;
ALTER TABLE `#__comm_subscribers` MODIFY `subscriber_surname` varchar(64) NOT NULL default '';