Verwenden von ALTER zum Löschen einer Spalte, falls diese in MySQL vorhanden ist

88

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

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

Ich verwende MySQL Version 4.0.18.

jcodeninja
quelle
6
Diese Frage wurde auf Meta erwähnt .
Nur ein Student

Antworten:

70

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

Dies zuzulassen ist wohl sowieso eine wirklich schlechte Idee: IF EXISTSZeigt an, dass Sie destruktive Operationen an einer Datenbank mit (Ihnen) unbekannter Struktur ausführen. Es kann Situationen geben, in denen dies für schnelle und schmutzige lokale Arbeiten akzeptabel ist. Wenn Sie jedoch versucht sind, eine solche Anweisung für Produktionsdaten (bei einer Migration usw.) auszuführen, spielen Sie mit dem Feuer.

Wenn Sie jedoch darauf bestehen, ist es nicht schwierig, zuerst im Client auf Existenz zu prüfen oder den Fehler zu erkennen.

MariaDB unterstützt ab 10.0.2 auch Folgendes:

DROP [COLUMN] [IF EXISTS] col_name 

dh

ALTER TABLE my_table DROP IF EXISTS my_column;

Aber es ist wohl eine schlechte Idee, sich auf eine nicht standardmäßige Funktion zu verlassen, die nur von einer von mehreren Gabeln von MySQL unterstützt wird.

Matthias Winkelmann
quelle
8
Gibt es eine Möglichkeit, dies in reinem SQL zu tun?
Tom
16
Beeindruckend. Erwähnt in 2005 - vor 9 Jahren. Ich
vermute,
4
MariaDB unterstützt es ab 10.0.2
Dfr
17
"Das zuzulassen ist wohl eine wirklich schlechte Idee" - ich stimme nicht zu. Warum sollte jemand Annahmen über Benutzeranwendungsfälle treffen? Ich habe eine Reihe von Datenbanken und muss sie synchronisieren. Es ist wirklich ärgerlich, wenn Software schlauer als Menschen sein will ...
Onkeltem
5
14 Jahre später immer noch nicht da. Ich glaube nicht, dass dies jemals geschehen wird.
Steve Horvath
44

In MySQL gibt es dafür keine Unterstützung auf Sprachebene. 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 einen Blog-Beitrag geschrieben .

Chase Seibert
quelle
3
Ich fand es wichtig, den Beitrag von DrHyde als Kommentar zusammenzufassen, da es nicht offensichtlich ist, wenn es sich um eine eigene Antwort handelt. Stellen Sie sicher, dass Sie keine andere Datenbank ändern: SELECT * from information_schema.columns WHERE table_name = "country" AND column_name = "aktualisiert_at" AND table_schema = DATABASE () \ G
Homer6
Wenn Sie keine Warnungen von "drop procedure falls vorhanden schema_change" erhalten möchten; add "set sql_notes = 0;" vor der ersten Zeile und fügen Sie "set sql_notes = 1;" nach der letzten Zeile. Details -> stackoverflow.com/questions/27616564/suppress-mysql-warnings
csonuryilmaz
"Trennzeichen" sollte ohne '' sein (zB -> Trennzeichen ;;)
Illidan
16

Ich weiß, dass dies ein alter Thread ist, aber es gibt eine einfache Möglichkeit, diese Anforderung zu handhaben, ohne gespeicherte Prozeduren zu verwenden. 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 ich (nach viel Versuch und Irrtum).

Pradeep Puranik
quelle
Das hat es sicher getan. Danke @Pradeep
Sumit Deshmukh
14

Ich habe gerade eine wiederverwendbare Prozedur erstellt, die dazu beitragen kann, DROP COLUMNidempotent zu machen:

-- 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
sp00m
quelle
5

Die Antwort von Chase Seibert funktioniert, aber ich möchte 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=...
DrHyde
quelle
1

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

  • CREATE new_table AS SELECT id, col1, col2, ... (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 bewahren Sie old_table für einen Rollback auf, 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 repariert werden (auf die neue my_table verwiesen).

Viel Glück...

Frank Flynn
quelle
1

Sie können dieses Skript verwenden und Ihren Spalten-, Schema- und Tabellennamen verwenden

 IF EXISTS (`enter code here`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;
Shah Zaiƞ
quelle
-3

Mir ist klar, dass dieser Thread jetzt ziemlich alt ist, aber ich hatte das gleiche Problem. Dies war meine grundlegende Lösung mit der MySQL Workbench, aber es hat gut funktioniert ...

  1. Holen Sie sich einen neuen SQL-Editor und führen Sie SHOW TABLES aus, um eine Liste Ihrer Tabellen zu erhalten
  2. Wählen Sie alle Zeilen aus und wählen Sie im Kontextmenü die Option In Zwischenablage kopieren (ohne Anführungszeichen)
  3. Fügen Sie die Liste der Namen in eine andere Editor-Registerkarte ein
  4. Schreiben Sie Ihre Anfrage, dh ALTER TABLE xDROP a;
  5. Kopieren und Einfügen, sodass Sie für jede Tabelle eine separate Abfrage erhalten
  6. Schalten Sie ein, ob die Workbench angehalten werden soll, wenn ein Fehler auftritt
  7. Klicken Sie auf Ausführen und durchsuchen Sie das Ausgabeprotokoll

Alle Tabellen, die die Tabelle hatten, haben jetzt keine Tabellen, die keinen Fehler in den Protokollen angezeigt haben

dann können Sie 'drop a' finden / ersetzen, es in 'ADD COLUMN bINT NULL' usw. ändern und das Ganze erneut ausführen ....

ein bisschen klobig, aber endlich erhalten Sie das Endergebnis und können den gesamten Prozess steuern / überwachen und daran denken, Ihre SQL-Skripte zu speichern, falls Sie sie erneut benötigen.

ajp
quelle