2009-08-27 5 views
1

SQL Server 데이터베이스의 경우 스키마 업데이트를 추적하기 위해 버전 관리 체계를 사용하고 있습니다. 스키마를 이전 버전에서 현재 버전으로 가져 오려면이 스크립트를 실행할 수 있어야합니다. 마스터 스크립트를 다시 실행하면 최신 스키마 업데이트 만 실행해야합니다.T-SQL "re-runnable"데이터베이스 업데이트 스크립트 - 열 삭제

스크립트의 구조는 다음과 같다 : 이것은 일반적으로 매우 잘 작동

SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=0 
IF (@Installed IS NULL) 
BEGIN 
    ... 
    INSERT INTO SystemSchemaVersion (Major, Minor, Patch, InstallDate) VALUES (1, 0, 0, GetDate()) 
END 
ELSE PRINT 'Version 1.0.0 was already installed on ' + Convert(varchar(10), @Installed) 

SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=1 
IF (@Installed IS NULL) 
BEGIN 
    ... 
    INSERT INTO SystemSchemaVersion (Major, Minor, Patch, InstallDate) VALUES (1, 0, 1, GetDate()) 
END 
ELSE PRINT 'Version 1.0.1 was already installed on ' + Convert(varchar(10), @Installed) 

. 그러나 스키마 업데이트가 이전 INSERT에 포함 된 열을 DROP 할 때 문제가 발생했습니다. 즉, 우리는 다음과 같은 것을 가지고 있습니다 :

SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=0 
IF (@Installed IS NULL) 
BEGIN 
    INSERT [foo] ([a], [b], [OrganizationId]) VALUES (N'a', N'b', N'1'); 
    INSERT INTO SystemSchemaVersion (Major, Minor, Patch, InstallDate) VALUES (1, 0, 0, GetDate()); 
END 
ELSE PRINT 'Version 1.0.0 was already installed on ' + Convert(varchar(10), @Installed) 

SELECT @Installed = InstallDate FROM SystemSchemaVersion WHERE Major=1 AND Minor=0 AND Patch=1 
IF (@Installed IS NULL) 
BEGIN 
    ALTER TABLE [foo] DROP COLUMN [OrganizationId]; 
    INSERT INTO SystemSchemaVersion (Major, Minor, Patch, InstallDate) VALUES (1, 0, 1, GetDate()); 
END 
ELSE PRINT 'Version 1.0.1 was already installed on ' + Convert(varchar(10), @Installed) 

이것은 처음 실행될 때 잘 동작합니다; 버전 1.0.1이 실행되고 열이 삭제됩니다. 그러나, 스크립트를 제 2 시간 수율 러닝이다

 Msg 207, Level 16, State 1, Line 7118 
    Invalid column name 'OrganizationId'. 

는 버전 1.0.0 블록 내부 INSERT가 실행되고 있지 않은 경우에도, 여전히 해석되고 그리고 잘못된 열의 오류를 발생시킨다.

이 문제를 해결하는 방법에 대한 제안 사항이 있으십니까? 이상적으로는 조건문을 사용하여 INSERT를 보호하여 구문 분석을 수행하지 않더라도 문제가 발생하지 않는 것으로 보입니다. sp_ExecuteSql() 호출 내에서 동적으로 INSERT를 수행 할 수는 있지만 (많은 갱신 작업이 필요하지는 않습니다).

감사합니다 -

--Andy

답변

1

좋아요, 처음에는 질문을 잘못 읽었습니다.

INSERT [foo] ([a], [b], [OrganizationId]) VALUES (N'a', N'b', N'1'); 

에 : 당신의 삽입 라인을 변경하는 경우 :-)

exec('INSERT [foo] ([a], [b], [OrganizationId]) VALUES (''a'', ''b'', ''1'')'); 

을 간부 인 원 안에 당신 '은 SQL 이후 "텍스트", 그 문제가 없어야합니다 exec()가 실제로 호출 될 때까지 까지 구문 분석됩니다.

+0

감사합니다. Ron. 기존에 생성 된 스크립트를 편집 할 수있는 대안이 있기를 바랬지 만 적어도 앞으로의 경로가 있습니다. –

1

는 불행하게도이 임시 테이블을 삭제 한 다음 다시 당신이 할 때 (proc 디렉토리에 저장 내에서) 얻을 문제와 유사하다. 파서는 임시 테이블이 삭제되었다는 것을 인식하지 못하고 이미 존재한다고 불평 할 것입니다.

GO 명령문을 사용하여 분리하면 시스템이 각 섹션을 재평가 할 것입니다.

Rob

0

우리는 스키마의 버전 관리를 위해 거의 동일한 설정을 사용합니다.

일반적으로 접근 방법은 완전히 정상입니다. 우리는 몇 년 동안이 일반적인 설정으로 실행 해 왔습니다. 기본적으로 파괴적인 또는 호환되지 않는 스키마 변경을 처리하기 위해 우리는 자동 CruiseControl.NET 빌드의 일부로 패치를 실행합니다.

그래서 우리의 데이터베이스 빌드
  • 는 현재 생산 버전 백업에서 복원 ... 다음과 같습니다.
  • 복원 된 버전 확인
  • [버전] 테이블에 표시된 버전보다 이후의 모든 패치 (이름은 major.minor.sql을 사용하여 규칙에 따라 지정됨)를 실행하십시오.

이렇게하면 패치가 무엇이든간에 문제없이 하루 종일 재구성 할 수 있습니다. 이것은 또한 우리가 PRODUCTION에 배포 할 때 이미 개발 중에 PRODUCTION db 1000x에 배포 했으므로 아무런 문제가 없음을 보장합니다.

0

동적 SQL을 사용해 보셨습니까? 슬프게도 파서는 스크립트를 실행하기 전에 전체 스크립트를 검사하므로 잘못된 열이 있으면 실행이 중지됩니다.