Sử dụng ALTER để thả một cột nếu nó tồn tại trong MySQL


92

Làm thế nào ALTER có thể được sử dụng để thả một cột trong bảng MySQL nếu cột đó tồn tại?

Tôi biết tôi có thể sử dụng ALTER TABLE my_table DROP COLUMN my_column, nhưng điều đó sẽ gây ra lỗi nếu my_columnkhông tồn tại. Có cú pháp thay thế nào để giảm cột có điều kiện không?

Tôi đang sử dụng MySQL phiên bản 4.0.18.


6
Câu hỏi này đã được đề cập trên Meta .
Chỉ là một sinh viên

Câu trả lời:


70

Đối với MySQL, không có: Yêu cầu tính năng MySQL .

Dù sao thì IF EXISTScho phép điều này được cho là một ý tưởng thực sự tồi: cho biết rằng bạn đang chạy các hoạt động phá hoại trên cơ sở dữ liệu có cấu trúc không xác định (đối với bạn). Có thể có những tình huống mà điều này có thể chấp nhận được đối với công việc cục bộ nhanh chóng và bẩn thỉu, nhưng nếu bạn muốn chạy một tuyên bố như vậy đối với dữ liệu sản xuất (trong quá trình di chuyển, v.v.), bạn đang chơi với lửa.

Nhưng nếu bạn nhấn mạnh, không khó để chỉ cần kiểm tra sự tồn tại trước tiên trong ứng dụng khách, hoặc bắt lỗi.

MariaDB cũng hỗ trợ những điều sau đây bắt đầu với 10.0.2:

DROP [COLUMN] [IF EXISTS] col_name 

I E

ALTER TABLE my_table DROP IF EXISTS my_column;

Nhưng được cho là một ý tưởng tồi nếu dựa vào một tính năng không chuẩn chỉ được hỗ trợ bởi một trong số nhiều nhánh của MySQL.


8
Có cách nào để làm điều đó trong SQL thuần túy không?
Tom

16
Chà. Được đề cập vào năm 2005 - 9 năm trước. Tôi đoán đây là xuống danh sách ưu tiên ...
crmpicco

4
MariaDB hỗ trợ nó bắt đầu từ 10.0.2
Dfr

17
“Cho phép điều này được cho là một ý tưởng thực sự tồi tệ,” - Tôi không đồng ý. Tại sao somone phải đưa ra giả định về các trường hợp sử dụng của người dùng? Tôi có một loạt cơ sở dữ liệu và tôi cần phải đồng bộ hóa chúng. Nó thực sự annoyoing khi phần mềm muốn được thông minh hơn con người ...
Onkeltem

5
14 năm trôi qua, vẫn không có. Tôi không nghĩ rằng điều này sẽ bao giờ được thực hiện.
Steve Horvath

45

Không có hỗ trợ cấp độ ngôn ngữ cho điều này trong MySQL. Đây là một giải pháp liên quan đến siêu dữ liệu MySQL information_schema trong 5.0+, nhưng nó sẽ không giải quyết vấn đề của bạn trong 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;

Tôi đã viết một số thông tin chi tiết hơn trong một bài đăng trên blog .


3
Tôi nghĩ điều quan trọng là phải tóm tắt đóng góp của DrHyde dưới dạng nhận xét, bởi vì nó không rõ ràng khi nó nằm trong một câu trả lời của chính nó. Đảm bảo rằng bạn không sửa đổi cơ sở dữ liệu khác: SELECT * from information_schema.columns WHERE table_name = "country" AND column_name = "updated_at" AND table_schema = DATABASE () \ G
Homer 6

Nếu bạn không muốn nhận cảnh báo từ "drop procedure nếu tồn tại schema_change;" thêm "set sql_notes = 0;" trước dòng đầu tiên và thêm "set sql_notes = 1;" sau dòng cuối cùng. Chi tiết -> stackoverflow.com/questions/27616564/suppress-mysql-warnings
csonuryilmaz

"dấu phân cách" không được không có '' (ví dụ -> dấu phân cách ;;)
Illidan

17

Tôi biết đây là một luồng cũ, nhưng có một cách đơn giản để xử lý yêu cầu này mà không cần sử dụng các thủ tục được lưu trữ. Điều này có thể giúp ai đó.

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 ;

Hy vọng điều này sẽ giúp ai đó, như tôi đã làm (sau rất nhiều lần thử và sai).


Nó chắc chắn đã làm. Cảm ơn @Pradeep
Sumit Deshmukh

14

Tôi vừa xây dựng một quy trình có thể tái sử dụng có thể giúp tạo ra DROP COLUMNIdempotent:

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

Sử dụng:

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

Thí dụ:

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

Câu trả lời của Chase Seibert hoạt động, nhưng tôi muốn nói thêm rằng nếu bạn có một số schemata, bạn muốn thay đổi SELECT do đó:

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

1

Có lẽ cách đơn giản nhất để giải quyết vấn đề này (sẽ hiệu quả) là:

  • TẠO new_table NHƯ CHỌN id, col1, col2, ... (chỉ các cột bạn thực sự muốn trong bảng cuối cùng) FROM my_table;

  • RENAME my_table TO old_table, new_table TO my_table;

  • DROP bảng cũ;

Hoặc giữ old_table để khôi phục nếu cần.

Điều này sẽ hoạt động nhưng các khóa ngoại sẽ không được di chuyển. Bạn sẽ phải thêm lại chúng vào my_table sau; cũng như các khóa ngoại trong các bảng khác tham chiếu đến my_table sẽ phải được sửa (trỏ đến my_table mới).

Chúc may mắn...


1

Bạn có thể sử dụng tập lệnh này, sử dụng cột, lược đồ và tên bảng của bạn

 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

Tôi nhận ra rằng chủ đề này đã khá cũ, nhưng tôi đã gặp phải vấn đề tương tự. Đây là giải pháp rất cơ bản của tôi bằng cách sử dụng MySQL Workbench, nhưng nó hoạt động tốt ...

  1. tải một trình soạn thảo sql mới và thực hiện SHOW TABLES để nhận danh sách các bảng của bạn
  2. chọn tất cả các hàng và chọn sao chép vào khay nhớ tạm (chưa được trích dẫn) từ menu ngữ cảnh
  3. dán danh sách tên vào một tab trình chỉnh sửa khác
  4. viết truy vấn của bạn, tức là ALTER TABLE xDROP a;
  5. thực hiện một số sao chép và dán, vì vậy bạn kết thúc với truy vấn riêng biệt cho mỗi bảng
  6. Chuyển đổi xem bàn làm việc có dừng lại khi xảy ra lỗi hay không
  7. Nhấn thực thi và xem qua nhật ký đầu ra

bất kỳ bảng nào có bảng bây giờ không có bất kỳ bảng nào không hiển thị lỗi trong nhật ký

sau đó bạn có thể tìm / thay thế 'drop a', thay đổi nó thành 'ADD COLUMN bINT NULL', v.v. và chạy lại toàn bộ ...

hơi rắc rối một chút, nhưng cuối cùng bạn sẽ nhận được kết quả cuối cùng và bạn có thể kiểm soát / giám sát toàn bộ quá trình và nhớ lưu lại các tập lệnh sql trong trường hợp bạn cần chúng một lần nữa.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.