使用ALTER删除列(如果它存在于MySQL中)


92

如果该列存在,如何使用ALTER将其删除到MySQL表中?

我知道我可以使用ALTER TABLE my_table DROP COLUMN my_column,但是如果my_column不存在则会抛出错误。是否有其他语法可有条件地删除列?

我正在使用MySQL版本4.0.18。


6
Meta上提到了这个问题。
只是一名学生

Answers:


70

对于MySQL,没有: MySQL Feature Request

无论如何,允许这样做是一个非常糟糕的主意:IF EXISTS表明您正在(具有)未知结构的数据库上运行破坏性操作。在某些情况下,这对于速干的本地工作是可以接受的,但是如果您想针对生产数据运行这样的语句(在迁移等过程中),那么您将大受打击。

但是,如果您坚持认为,则不难先在客户端中先检查是否存在,或捕获错误。

MariaDB还从10.0.2开始支持以下内容:

DROP [COLUMN] [IF EXISTS] col_name 

ALTER TABLE my_table DROP IF EXISTS my_column;

但是,仅依靠MySQL的几个分支之一支持的非标准功能可能是一个坏主意。


8
有没有办法在纯SQL中做到这一点?
汤姆(Tom)2010年

16
哇。提到2005年-9年前。我猜这不在优先列表中……
crmpicco

4
MariaDB支持从10.0.2
Dfr

17
“允许这样做可以说是一个非常糟糕的主意,” –我不同意。为什么somone会对用户用例做出假设?我有一堆数据库,需要同步它们。当软件想要比人类更智能时,这真令人讨厌……
Onkeltem

5
14年了,仍然不存在。我认为这不会完成。
史蒂夫·霍瓦斯

45

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;

我在博客文章中写了一些更详细的信息。


3
我认为将DrHyde的贡献​​总结为评论很重要,因为在回答自己的问题时并不清楚。确保检查您是否未修改其他数据库:SELECT * from information_schema.columns其中table_name =“ country” AND column_name =“ updated_at” AND table_schema = DATABASE()\ G
Homer6,2011年

如果您不想从“如果存在schema_change,则删除过程”中获得警告。添加“设置sql_notes = 0;” 在第一行之前添加“ set sql_notes = 1;” 最后一行之后。详细信息-> stackoverflow.com/questions/27616564/suppress-mysql-warnings
csonuryilmaz

“定界符”应不包含“”(例如->定界符;;)
伊利丹

17

我知道这是一个旧线程,但是有一种无需使用存储过程即可处理此要求的简单方法。这可能会帮助某人。

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 ;

希望这对某人有帮助,就像我所做的那样(经过大量的试验和错误)。


当然可以。感谢@Pradeep
Sumit Deshmukh

14

我刚刚建立了一个可重用的过程,可以帮助使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

5

蔡斯·塞伯特(Chase Seibert)的答案行得通,但我要补充一点,如果您有多个模式,则要更改SELECT:

select * from information_schema.columns where table_schema in (select schema()) and table_name=...

1

解决这个问题(最有效的方法)的最简单方法可能是:

  • 从my_table创建new_table AS SELECT id,col1,col2,...(仅最终表中实际需要的列);

  • 重命名my_table到old_table,new_table到my_table;

  • DROP old_table;

或者,如果需要,请保留old_table进行回滚。

这将起作用,但是外键将不会移动。您将不得不稍后将它们重新添加到my_table中;另外,引用my_table的其他表中的外键也必须固定(指向新的my_table)。

祝好运...



-3

我知道这个线程现在已经很旧了,但是我遇到了同样的问题。这是我使用MySQL Workbench的最基本的解决方案,但效果很好。

  1. 获取一个新的sql编辑器并执行SHOW TABLES以获取表列表
  2. 选择所有行,然后从上下文菜单中选择“复制到剪贴板(不带引号)”
  3. 将名称列表粘贴到另一个编辑器选项卡中
  4. 编写查询,即ALTER TABLE xDROP a
  5. 进行一些复制和粘贴,因此最终每个表都有单独的查询
  6. 切换发生错误时工作台是否应停止
  7. 点击执行并查看输出日志

现在具有该表的所有表都没有该表的任何表,它们将在日志中显示错误

那么您可以查找/替换'drop a'并将其更改为'ADD COLUMN bINT NULL'等,然后再次运行整个过程...。

有点笨拙,但是最后您得到了最终结果,您可以控制/监视整个过程,并记得保存您的sql脚本,以防万一您再次需要它们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.