Використання ALTER для скидання стовпця, якщо він існує в MySQL


92

Як можна використовувати ALTER для скидання стовпця в таблицю MySQL, якщо такий стовпець існує?

Я знаю, що можу використовувати ALTER TABLE my_table DROP COLUMN my_column, але це призведе до помилки, якщо my_columnне існує. Чи існує альтернативний синтаксис умовного скидання стовпця?

Я використовую MySQL версії 4.0.18.


6
Це питання згадувалося на Мета .
Просто студент

Відповіді:


70

Для MySQL не існує жодного: Запит функції MySQL .

У будь-якому випадку дозволити це, мабуть, насправді погана ідея: IF EXISTSвказує на те, що ви виконуєте руйнівні операції з базою даних із (для вас) невідомою структурою. Можуть бути ситуації, коли це прийнятно для швидкої та брудної локальної роботи, але якщо у вас виникає спокуса запустити таку заяву проти виробничих даних (при міграції тощо), ви граєтеся з вогнем.

Але якщо ви наполягаєте, неважко просто перевірити наявність клієнта спочатку або виявити помилку.

MariaDB також підтримує наступне, починаючи з 10.0.2:

DROP [COLUMN] [IF EXISTS] col_name 

тобто

ALTER TABLE my_table DROP IF EXISTS my_column;

Але, мабуть, погана ідея покладатися на нестандартну функцію, що підтримується лише однією з декількох форків MySQL.


8
Чи є спосіб це зробити в чистому SQL?
Том,

16
Ого. Згадується у 2005 - 9 роках тому. Я здогадуюсь, це в списку пріоритетів ...
crmpicco

4
MariaDB підтримує це, починаючи з 10.0.2
пн

17
"Дозволити це, мабуть, насправді погана ідея", - я не згоден. Чому somone повинен робити припущення щодо випадків використання користувачів? У мене є купа баз даних, і мені потрібно синхронізувати їх. Це насправді дратує, коли програмне забезпечення хоче бути розумнішим за людей ...
Онкельтем,

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" AND 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 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

Відповідь Чейза Сейберта працює, але я б додав, що якщо у вас є кілька схем, ви хочете змінити SELECT таким чином:

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

1

Мабуть, найпростіший спосіб вирішити це (що спрацює):

  • СТВОРИТИ new_table AS SELECT id, col1, col2, ... (лише ті стовпці, які ви насправді бажаєте у кінцевій таблиці) FROM my_table;

  • ПЕРЕМЕНУВАТИ my_table TO 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 COLUMN bINT NULL" і т.д. і запустити все це знову ....

трохи незграбний, але нарешті ви отримуєте кінцевий результат, і ви можете контролювати / контролювати весь процес і не забувати економити ваші сценарії sql, якщо вони вам знову знадобляться.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.