내 연구와 실험이 아직 답을 얻지 못했기 때문에 도움이 필요합니다.
이전 버전에서 지금 추가하고 싶은 열이 없었던 응용 프로그램의 설치 파일을 수정하고 있습니다. 열을 수동으로 추가하지 않고 설치 파일에 새 열이 테이블에 아직없는 경우에만 추가하고 싶습니다.
테이블은 다음과 같이 생성됩니다.
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 ;