it-swarm.com.de

Verwenden Sie ALTER, um eine Spalte zu löschen, wenn sie in MySQL vorhanden ist

Wie kann ALTER verwendet werden, um eine Spalte in einer MySQL-Tabelle zu löschen, wenn diese Spalte existiert?

Ich weiß, ich kann ALTER TABLE my_table DROP COLUMN my_column, aber das wird einen Fehler auslösen, wenn my_column ist nicht vorhanden. Gibt es eine alternative Syntax zum bedingten Löschen der Spalte?

Ich benutze MySQL Version 4.0.18.

71
jcodeninja

Für MySQL gibt es keine: MySQL Feature Request .

Das zuzulassen, ist ohnehin eine wirklich schlechte Idee: IF EXISTS gibt an, dass Sie destruktive Vorgänge für eine Datenbank mit (für Sie) unbekannter Struktur ausführen. Es kann Situationen geben, in denen dies für eine schnelle und schmutzige Arbeit vor Ort akzeptabel ist. Wenn Sie jedoch versucht sind, eine solche Anweisung für Produktionsdaten auszuführen (bei einer Migration usw.), spielen Sie mit dem Feuer.

Wenn Sie jedoch darauf bestehen, ist es nicht schwierig, zunächst im Client auf Existenz zu prüfen oder den Fehler abzufangen.

MariaDB unterstützt außerdem Folgendes ab 10.0.2:

DROP [COLUMN] [WENN EXISTS] col_name

ich. e.

ALTER TABLE my_table DROP WENN EXISTS my_column;

Es ist jedoch wahrscheinlich eine schlechte Idee, sich auf ein nicht standardmäßiges Feature zu verlassen, das nur von einer von mehreren Forks von MySQL unterstützt wird.

53
MattW.

In MySQL gibt es hierfür keine Sprachunterstützung. Hier ist eine Problemumgehung mit MySQL information_schema-Metadaten in 5.0+, die Ihr Problem in 4.0.18 jedoch nicht behebt.

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;

Ich habe einige detailliertere Informationen in einem Blog-Beitrag geschrieben.

42
Chase Seibert

Ich weiß, dass dies ein alter Thread ist, aber es gibt eine einfache Möglichkeit, diese Anforderung ohne Verwendung gespeicherter Prozeduren zu handhaben. Dies kann jemandem helfen.

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 ;

Hoffe das hilft jemandem, so wie es mir geholfen hat (nach viel Ausprobieren).

11
Pradeep Puranik

Ich habe gerade eine wiederverwendbare Prozedur erstellt, die dazu beitragen kann, DROP COLUMN idempotent:

-- 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 ;

Verwendung:

CALL drop_column_if_exists('my_table', 'my_column');

Beispiel:

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
10
sp00m

Chase Seiberts Antwort funktioniert, aber ich würde hinzufügen, dass Sie, wenn Sie mehrere Schemata haben, das SELECT folgendermaßen ändern möchten:

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

Vielleicht ist der einfachste Weg, dies zu lösen (das wird funktionieren):

  • CREATE new_table AS SELECT ID, Spalte1, Spalte2, ... (nur die Spalten, die Sie tatsächlich in der endgültigen Tabelle haben möchten) FROM my_table;

  • RENAME my_table TO old_table, new_table TO my_table;

  • DROP old_table;

Oder behalten Sie old_table für ein Rollback bei, falls erforderlich.

Dies funktioniert, aber Fremdschlüssel werden nicht verschoben. Sie müssten sie später erneut zu my_table hinzufügen. Auch Fremdschlüssel in anderen Tabellen, die auf my_table verweisen, müssen korrigiert werden (auf die neue my_table zeigen).

Viel Glück...

0
Frank Flynn