[mysql] 존재하지 않는 경우 mysql 테이블에 열 추가

내 연구와 실험이 아직 답을 얻지 못했기 때문에 도움이 필요합니다.

이전 버전에서 지금 추가하고 싶은 열이 없었던 응용 프로그램의 설치 파일을 수정하고 있습니다. 열을 수동으로 추가하지 않고 설치 파일에 새 열이 테이블에 아직없는 경우에만 추가하고 싶습니다.

테이블은 다음과 같이 생성됩니다.

CREATE TABLE IF NOT EXISTS `#__comm_subscribers` (
      `subscriber_id` int(11) NOT NULL auto_increment,
      `user_id` int(11) NOT NULL default '0',
      `subscriber_name` varchar(64) NOT NULL default '',
      `subscriber_surname` varchar(64) NOT NULL default '',
      `subscriber_email` varchar(64) NOT NULL default '',
      `confirmed` tinyint(1) NOT NULL default '0',
      `subscribe_date` datetime NOT NULL default '0000-00-00 00:00:00',
      PRIMARY KEY  (`subscriber_id`),
      UNIQUE KEY `subscriber_email` (`subscriber_email`)
    ) ENGINE=MyISAM CHARACTER SET 'utf8' COLLATE 'utf8_general_ci' COMMENT='Subscribers for Comm are stored here.';

create table 문 아래에 다음을 추가하면 열이 이미 존재하고 채워지면 어떻게되는지 확실하지 않습니다.

ALTER TABLE `#__comm_subscribers` ADD `subscriber_surname`;
ALTER TABLE `#__comm_subscribers` MODIFY `subscriber_surname` varchar(64) NOT NULL default '';

그래서 어딘가에서 찾은 다음을 시도했습니다. 이것은 작동하지 않는 것 같지만 제대로 사용했는지 완전히 확신하지 못합니다.

/*delimiter '//'
CREATE PROCEDURE addcol() BEGIN
IF NOT EXISTS(
SELECT * FROM information_schema.COLUMNS
WHERE COLUMN_NAME='subscriber_surname' AND TABLE_NAME='#__comm_subscribers'
)
THEN
    ALTER TABLE `#__comm_subscribers`
    ADD COLUMN `subscriber_surname` varchar(64) NOT NULL default '';
END IF;
END;
//
delimiter ';'
CALL addcol();
DROP PROCEDURE addcol;*/

누구든지 이것을 할 좋은 방법이 있습니까?



답변

참고 INFORMATION_SCHEMA이전 5.0에 MySQL을 지원하지 않습니다. 5.0 이전에는 저장 프로 시저가 지원되지 않으므로 MySQL 4.1을 지원해야하는 경우이 솔루션은 좋지 않습니다.

데이터베이스 마이그레이션 을 사용하는 프레임 워크에서 사용하는 한 가지 솔루션 은 스키마의 개정 번호를 데이터베이스에 기록하는 것입니다. 단일 열과 단일 행이있는 테이블이며 현재 유효한 개정을 나타내는 정수가 있습니다. 스키마를 업데이트 할 때 숫자를 늘립니다.

또 다른 해결책은 명령을 시도 하는 것 ALTER TABLE ADD COLUMN입니다. 열이 이미 있으면 오류가 발생합니다.

ERROR 1060 (42S21): Duplicate column name 'newcolumnname'

오류를 포착하고 업그레이드 스크립트에서 무시하십시오.


답변

다음은 작동하는 솔루션입니다 (Solaris에서 MySQL 5.0을 사용해 보았습니다).

DELIMITER $$

DROP PROCEDURE IF EXISTS upgrade_database_1_0_to_2_0 $$
CREATE PROCEDURE upgrade_database_1_0_to_2_0()
BEGIN

-- rename a table safely
IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()
        AND TABLE_NAME='my_old_table_name') ) THEN
    RENAME TABLE
        my_old_table_name TO my_new_table_name,
END IF;

-- add a column safely
IF NOT EXISTS( (SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE()
        AND COLUMN_NAME='my_additional_column' AND TABLE_NAME='my_table_name') ) THEN
    ALTER TABLE my_table_name ADD my_additional_column varchar(2048) NOT NULL DEFAULT '';
END IF;

END $$

CALL upgrade_database_1_0_to_2_0() $$

DELIMITER ;

언뜻보기에는 생각보다 복잡해 보이지만 여기서는 다음과 같은 문제를 처리해야합니다.

  • IF 명령문은 저장 프로 시저에서만 작동하며 직접 실행될 때는 작동하지 않습니다 (예 : mysql 클라이언트).
  • 더 우아하고 간결한 SHOW COLUMNS것은 저장 프로 시저에서 작동하지 않으므로 INFORMATION_SCHEMA를 사용해야합니다.
  • MySQL에서는 문을 구분하는 구문이 이상하므로 저장 프로 시저를 만들 수 있으려면 구분 기호를 다시 정의해야합니다. 구분 기호를 다시 바꾸는 것을 잊지 마십시오!
  • INFORMATION_SCHEMA는 모든 데이터베이스에 대해 전역이므로에서 필터링하는 것을 잊지 마십시오 TABLE_SCHEMA=DATABASE(). DATABASE()현재 선택된 데이터베이스의 이름을 반환합니다.

답변

MariaDB를 사용하는 경우 저장 프로 시저를 사용할 필요가 없습니다. 예를 들어 다음을 사용하십시오.

ALTER TABLE table_name ADD COLUMN IF NOT EXISTS column_name tinyint(1) DEFAULT 0;

여기를 보아라


답변

대부분의 답변은 저장 프로 시저에서 안전하게 열을 추가하는 방법을 다루고 있으며, 저장 프로 시저를 사용하지 않고 안전하게 테이블에 열을 추가해야했고 MySQL이 SPIF Exists() 외부 의 사용을 허용하지 않는다는 것을 발견했습니다 . 같은 상황에있는 사람에게 도움이 될 수있는 솔루션을 게시하겠습니다.

SELECT count(*)
INTO @exist
FROM information_schema.columns
WHERE table_schema = database()
and COLUMN_NAME = 'original_data'
AND table_name = 'mytable';

set @query = IF(@exist <= 0, 'alter table intent add column mycolumn4 varchar(2048) NULL after mycolumn3',
'select \'Column Exists\' status');

prepare stmt from @query;

EXECUTE stmt;


답변

이를 수행하는 또 다른 방법은 다음과 같이 오류를 무시하는 것입니다 declare continue handler.

delimiter ;;
create procedure foo ()
begin
    declare continue handler for 1060 begin end;
    alter table atable add subscriber_surname varchar(64);
end;;
call foo();;

나는 exists하위 쿼리 보다 이런 식으로 깔끔하다고 생각합니다 . 특히 추가 할 열이 많고 스크립트를 여러 번 실행하려는 경우.

계속 처리기에 대한 자세한 내용은 http://dev.mysql.com/doc/refman/5.0/en/declare-handler.html 에서 찾을 수 있습니다.


답변

MySQL 5.5.19를 사용하고 있습니다.

특히 오류 / 경고가없는 스크립트를 실행하는 동안 나중에 다시 표시되는 경고가 남아있는 것처럼 오류없이 실행하고 다시 실행할 수있는 스크립트를 좋아합니다. 필드 추가에 관한 한, 필자는 입력을 줄이는 절차를 직접 작성했습니다.

-- add fields to template table to support ignoring extra data 
-- at the top/bottom of every page
CALL addFieldIfNotExists ('template', 'firstPageHeaderEndY', 'INT NOT NULL DEFAULT 0');
CALL addFieldIfNotExists ('template', 'pageHeaderEndY', 'INT NOT NULL DEFAULT 0');
CALL addFieldIfNotExists ('template', 'pageFooterBeginY', 'INT NOT NULL DEFAULT 792');

addFieldIfNotExists 프로 시저 를 만드는 코드 는 다음과 같습니다.

DELIMITER $$

DROP PROCEDURE IF EXISTS addFieldIfNotExists
$$

DROP FUNCTION IF EXISTS isFieldExisting
$$

CREATE FUNCTION isFieldExisting (table_name_IN VARCHAR(100), field_name_IN VARCHAR(100))
RETURNS INT
RETURN (
    SELECT COUNT(COLUMN_NAME)
    FROM INFORMATION_SCHEMA.columns
    WHERE TABLE_SCHEMA = DATABASE()
    AND TABLE_NAME = table_name_IN
    AND COLUMN_NAME = field_name_IN
)
$$

CREATE PROCEDURE addFieldIfNotExists (
    IN table_name_IN VARCHAR(100)
    , IN field_name_IN VARCHAR(100)
    , IN field_definition_IN VARCHAR(100)
)
BEGIN

    -- http://javajon.blogspot.com/2012/10/mysql-alter-table-add-column-if-not.html

    SET @isFieldThere = isFieldExisting(table_name_IN, field_name_IN);
    IF (@isFieldThere = 0) THEN

        SET @ddl = CONCAT('ALTER TABLE ', table_name_IN);
        SET @ddl = CONCAT(@ddl, ' ', 'ADD COLUMN') ;
        SET @ddl = CONCAT(@ddl, ' ', field_name_IN);
        SET @ddl = CONCAT(@ddl, ' ', field_definition_IN);

        PREPARE stmt FROM @ddl;
        EXECUTE stmt;
        DEALLOCATE PREPARE stmt;

    END IF;

END;
$$

컬럼을 안전하게 수정하기위한 프로 시저를 작성하지는 않았지만 위의 프로시 저는 쉽게 수정 될 수 있다고 생각합니다.


답변

나는 OP의 sproc을 가져 와서 재사용 가능하고 스키마 독립적으로 만들었습니다. 분명히 여전히 MySQL 5가 필요합니다.

DROP PROCEDURE IF EXISTS AddCol;

DELIMITER //

CREATE PROCEDURE AddCol(
    IN param_schema VARCHAR(100),
    IN param_table_name VARCHAR(100),
    IN param_column VARCHAR(100),
    IN param_column_details VARCHAR(100)
)
BEGIN
    IF NOT EXISTS(
    SELECT NULL FROM information_schema.COLUMNS
    WHERE COLUMN_NAME=param_column AND TABLE_NAME=param_table_name AND table_schema = param_schema
    )
    THEN
        set @paramTable = param_table_name ;
        set @ParamColumn = param_column ;
        set @ParamSchema = param_schema;
        set @ParamColumnDetails = param_column_details;
        /* Create the full statement to execute */
        set @StatementToExecute = concat('ALTER TABLE `',@ParamSchema,'`.`',@paramTable,'` ADD COLUMN `',@ParamColumn,'` ',@ParamColumnDetails);
        /* Prepare and execute the statement that was built */
        prepare DynamicStatement from @StatementToExecute ;
        execute DynamicStatement ;
        /* Cleanup the prepared statement */
        deallocate prepare DynamicStatement ;

    END IF;
END //

DELIMITER ;