【发布时间】:2010-09-15 11:40:59
【问题描述】:
如果存在 MySQL 表中的列,如何使用 ALTER 删除该列?
我知道我可以使用ALTER TABLE my_table DROP COLUMN my_column,但如果my_column 不存在,则会引发错误。有条件删除列的替代语法吗?
我使用的是 MySQL 4.0.18 版。
【问题讨论】:
-
Meta提到了这个问题。
如果存在 MySQL 表中的列,如何使用 ALTER 删除该列?
我知道我可以使用ALTER TABLE my_table DROP COLUMN my_column,但如果my_column 不存在,则会引发错误。有条件删除列的替代语法吗?
我使用的是 MySQL 4.0.18 版。
【问题讨论】:
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;
对于 MySQL,没有: MySQL Feature Request。
无论如何,允许这样做可以说是一个非常糟糕的主意:IF EXISTS 表示您正在对具有(对您而言)未知结构的数据库运行破坏性操作。在某些情况下,这对于快速而肮脏的本地工作来说是可以接受的,但如果您想针对生产数据运行这样的语句(在迁移等中),那么您就是在玩火。
但如果你坚持,首先在客户端简单地检查是否存在,或者捕获错误并不难。
MariaDB 从 10.0.2 开始还支持以下内容:
DROP [COLUMN] [IF EXISTS] col_name
我。 e.
ALTER TABLE my_table DROP IF EXISTS my_column;
但可以说,依赖仅由 MySQL 的几个分支之一支持的非标准特性是一个坏主意。
【讨论】:
也许解决这个问题的最简单方法(可行)是:
CREATE new_table AS SELECT id, col1, col2, ...(仅在最终表中您真正想要的列) FROM my_table;
将 my_table 重命名为 old_table,将 new_table 重命名为 my_table;
删除旧表;
如果需要,也可以保留 old_table 以备回滚。
这会起作用,但不会移动外键。您必须稍后将它们重新添加到 my_table ;还必须修复引用 my_table 的其他表中的外键(指向新的 my_table)。
祝你好运……
【讨论】:
我刚刚构建了一个可重用的过程,可以帮助使DROP COLUMN 幂等:
-- 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 ;
用法:
CALL drop_column_if_exists('my_table', 'my_column');
例子:
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
【讨论】:
我知道这是一个旧线程,但有一种简单的方法可以在不使用存储过程的情况下处理此要求。这可能对某人有所帮助。
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 ;
希望这对某人有所帮助,就像对我一样(经过大量试验和错误)。
【讨论】:
在 MySQL 中对此没有语言级别的支持。这是 5.0+ 中涉及 MySQL information_schema 元数据的解决方法,但它不会解决您在 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;
我在blog post中写了一些更详细的信息。
【讨论】:
我意识到这个线程现在已经很老了,但我遇到了同样的问题。 这是我使用 MySQL Workbench 的非常基本的解决方案,但效果很好......
x DROP a;任何有桌子的桌子现在都没有 任何未在日志中显示错误的表
然后您可以找到/替换 'drop a' 将其更改为 'ADD COLUMN b INT NULL' 等,然后再次运行整个过程......
有点笨拙,但最后你得到了最终结果,你可以控制/监控整个过程,记得保存你的 sql 脚本以防你再次需要它们。
【讨论】:
Chase Seibert 的回答有效,但我想补充一点,如果您有多个模式,您想因此更改 SELECT:
select * from information_schema.columns where table_schema in (select schema()) and table_name=...
【讨论】: