여러 개발 데이터베이스의 변경 사항을 스테이징 / 프로덕션으로 자동 마이그레이션하는 스크립트를 생성하고 있습니다. 기본적으로 많은 변경 스크립트를 사용하여 단일 스크립트로 병합하여 각 스크립트를 IF whatever BEGIN ... END
명령문으로 래핑 합니다.
그러나 일부 스크립트에는 GO
예를 들어 SQL 파서가 새 열이 생성 된 후 새 열에 대해 알 수 있도록 문이 필요합니다 .
ALTER TABLE dbo.EMPLOYEE
ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO -- Necessary, or next line will generate "Unknown column: EMP_IS_ADMIN"
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
그러나 일단 IF
블록으로 감싸면 다음과 같습니다.
IF whatever
BEGIN
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
END
BEGIN
일치하지 않는를 보내고 있기 때문에 실패합니다 END
. 그러나 내가 제거 GO
하면 알 수없는 열에 대해 다시 불평합니다.
단일 IF
블록 내에서 동일한 열을 만들고 업데이트하는 방법이 있습니까?
답변
나는 같은 문제가 있었고 마침내 SET NOEXEC를 사용하여 해결했습니다 .
IF not whatever
BEGIN
SET NOEXEC ON;
END
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
SET NOEXEC OFF;
답변
GO
SQL이 아닙니다. 일부 MS SQL 도구에서 사용되는 배치 구분 기호 일뿐입니다.
이를 사용하지 않으면 명령문이 개별적으로 실행되는지 확인해야합니다. 다른 배치에서 또는 모집단에 대한 동적 SQL을 사용하여 (@gbn에게 감사드립니다) :
IF whatever
BEGIN
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL;
EXEC ('UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever')
END
답변
당신은 시도해 볼 수도 있습니다 sp_executesql
각각의 내용을 분할, GO
아래 예제와 같이 별도의 문자열로 문을 실행 할 수 있습니다. 또한 예외가 발생한 위치를 쉽게 디버깅 할 수 있도록 실행중인 문을 추적하는 @statementNo 변수가 있습니다. 줄 번호는 오류를 일으킨 관련 명령문 번호의 시작 부분을 기준으로합니다.
BEGIN TRAN
DECLARE @statementNo INT
BEGIN TRY
IF 1=1
BEGIN
SET @statementNo = 1
EXEC sp_executesql
N' ALTER TABLE dbo.EMPLOYEE
ADD COLUMN EMP_IS_ADMIN BIT NOT NULL'
SET @statementNo = 2
EXEC sp_executesql
N' UPDATE dbo.EMPLOYEE
SET EMP_IS_ADMIN = 1'
SET @statementNo = 3
EXEC sp_executesql
N' UPDATE dbo.EMPLOYEE
SET EMP_IS_ADMIN = 1x'
END
END TRY
BEGIN CATCH
PRINT 'Error occurred on line ' + cast(ERROR_LINE() as varchar(10))
+ ' of ' + 'statement # ' + cast(@statementNo as varchar(10))
+ ': ' + ERROR_MESSAGE()
-- error occurred, so rollback the transaction
ROLLBACK
END CATCH
-- if we were successful, we should still have a transaction, so commit it
IF @@TRANCOUNT > 0
COMMIT
또한 위의 예에서 설명한 것처럼 작은 따옴표 ( '
) 로 묶어 여러 줄 문을 쉽게 실행할 수 있습니다 . ''
스크립트를 생성 할 때 문자열 안에 포함 된 작은 따옴표를 큰 따옴표 ( ) 로 이스케이프하는 것을 잊지 마십시오 .
답변
궁극적으로 GO
자체 라인 의 모든 인스턴스 를
END
GO
---Automatic replacement of GO keyword, need to recheck IF conditional:
IF whatever
BEGIN
이 문자열에 문의 모든 그룹을 포장에 매우 바람직하지만 여전히 멀리 이상적에서. 누구든지 더 나은 해결책을 찾으면 게시하고 대신 수락하겠습니다.
답변
GO inbetween 대신 BEGIN 및 END로 명령문을 묶을 수 있습니다.
IF COL_LENGTH('Employees','EMP_IS_ADMIN') IS NULL --Column does not exist
BEGIN
BEGIN
ALTER TABLE dbo.Employees ADD EMP_IS_ADMIN BIT
END
BEGIN
UPDATE EMPLOYEES SET EMP_IS_ADMIN = 0
END
END
(Northwind 데이터베이스에서 테스트 됨)
편집 : (아마 SQL2012에서 테스트 됨)
답변
이 솔루션을 시도해 볼 수 있습니다.
if exists(
SELECT...
)
BEGIN
PRINT 'NOT RUN'
RETURN
END
--if upper code not true
ALTER...
GO
UPDATE...
GO
답변
나는 RAISERROR
이것을 위해 과거에 사용했습니다
IF NOT whatever BEGIN
RAISERROR('YOU''RE ALL SET, and sorry for the error!', 20, -1) WITH LOG
END
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever