[sql] TSQL-BEGIN .. END 블록 내에서 GO를 사용하는 방법?

여러 개발 데이터베이스의 변경 사항을 스테이징 / 프로덕션으로 자동 마이그레이션하는 스크립트를 생성하고 있습니다. 기본적으로 많은 변경 스크립트를 사용하여 단일 스크립트로 병합하여 각 스크립트를 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