Использование ALTER для удаления столбца, если он существует в MySQL

92

Как можно использовать ALTER для удаления столбца в таблице MySQL, если этот столбец существует?

Я знаю, что могу использовать ALTER TABLE my_table DROP COLUMN my_column, но это вызовет ошибку, если my_columnего не существует. Есть ли альтернативный синтаксис для условного удаления столбца?

Я использую MySQL версии 4.0.18.

jcodeninja
источник
6
Этот вопрос был упомянут на Мета .
Просто студент

Ответы:

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
16
Вау. Упоминался в 2005 году - 9 лет назад. Я предполагаю, что это в списке приоритетов ...
crmpicco
4
MariaDB поддерживает его , начиная с 10.0.2
DFR
17
«Допустить это, пожалуй, действительно плохая идея», - не согласен. Почему кому-то следует делать предположения о вариантах использования пользователей? У меня есть куча баз данных, и мне нужно их синхронизировать. Это действительно раздражает, когда программное обеспечение хочет быть умнее человека ...
Onkeltem
5
14 лет спустя, все еще нет. Я не думаю, что это когда-нибудь удастся сделать.
Стив Хорват
45

В MySQL для этого нет поддержки языкового уровня. Вот обходной путь с использованием метаданных MySQL information_schema в версии 5.0+, но он не решит вашу проблему в версии 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 WHERE table_name = "country" AND column_name = "updated_at" И table_schema = DATABASE () \ G
Homer6
Если вы не хотите получать предупреждения от «процедуры удаления, если существует 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
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
sp00m
источник
5

Ответ Чейза Зайберта работает, но я бы добавил, что если у вас есть несколько схем, вы хотите изменить SELECT следующим образом:

select * from information_schema.columns where table_schema in (select schema()) and table_name=...
DrHyde
источник
1

Возможно, самый простой способ решить эту проблему (который будет работать):

  • СОЗДАТЬ новую_таблицу КАК ВЫБРАТЬ id, col1, col2, ... (только те столбцы, которые вам действительно нужны в конечной таблице) FROM my_table;

  • ПЕРЕИМЕНОВАТЬ my_table в old_table, new_table TO my_table;

  • DROP old_table;

Или оставьте old_table для отката при необходимости.

Это будет работать, но внешние ключи не будут перемещены. Позже вам придется повторно добавить их в my_table; также внешние ключи в других таблицах, которые ссылаются на my_table, должны быть исправлены (указываются на новую my_table).

Удачи...

Фрэнк Флинн
источник
1

Вы можете использовать этот скрипт, использовать свой столбец, схему и имя таблицы

 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;
Шах Зайо
источник
-3

Я понимаю, что эта ветка сейчас довольно старая, но у меня была та же проблема. Это было мое очень простое решение с использованием MySQL Workbench, но оно работало нормально ...

  1. получите новый редактор sql и выполните SHOW TABLES, чтобы получить список ваших таблиц
  2. выберите все строки и выберите копировать в буфер обмена (без кавычек) из контекстного меню
  3. вставить список имен в другую вкладку редактора
  4. напишите свой запрос, т.е. ALTER TABLE xDROP a;
  5. сделайте некоторое копирование и вставку, так что вы получите отдельный запрос для каждой таблицы
  6. Переключить, должна ли рабочая среда останавливаться при возникновении ошибки
  7. Нажмите "Выполнить" и просмотрите выходной журнал.

любые таблицы, в которых была таблица, теперь не имеют таблиц, которые не отображали бы ошибку в журналах

тогда вы можете найти / заменить 'drop a' измените его на 'ADD COLUMNb INT NULL' и т.д. и снова запустить все это ....

немного неуклюже, но, наконец, вы получаете конечный результат, и вы можете контролировать / отслеживать весь процесс и не забывать сохранять свои sql-скрипты на случай, если они вам снова понадобятся.

ajp
источник