존재하지 않는 코드로 새로운 함수 생성


15

데이터베이스에서 스크립트로 새로운 기능을 만들고 싶습니다. 스크립트 코드는 다음과 같습니다.

IF Exists(Select * From sys.sysobjects A Where A.name =N'fn_myfunc' and xtype=N'FN') return;

CREATE FUNCTION fn_myfunc ()
returns varchar(10)
AS Begin
...
End

그러나 위의 스크립트를 실행하면 SQL Server가 오류를 반환합니다.

'CREATE FUNCTION' must be the first statement in a query batch.

답변:


16

2017 년 1 월 업데이트-SQL Server 2016+ / Azure SQL Database

SQL Server 2016 및 현재 버전의 Azure SQL Database에는 이제 함수, 프로 시저, 테이블, 데이터베이스 등에 대한 다음 구문이 있습니다 ( DROP IF EXISTS).

DROP FUNCTION IF EXISTS dbo.fn_myfunc;

또한 SQL Server 2016 서비스 팩 1은 모듈 (기능, 프로 시저, 트리거, 뷰)에 더 나은 기능을 추가하여 권한 또는 종속성의 손실이 없음을 의미합니다 ( CREATE OR ALTER).

CREATE OR ALTER FUNCTION dbo.fn_myfunc ...

이러한 구문 향상은 소스 제어, 배포 등에 사용되는 훨씬 간단한 스크립트로 이어질 수 있습니다.

하지만 사용중인 경우 ...


이전 버전

Management Studio에서이를 스크립팅 할 때 SQL Server가 수행하는 작업을 수행해야합니다.

IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE type = 'FN' AND name = 'fn_myfunc')
BEGIN
    DECLARE @sql NVARCHAR(MAX);
    SET @sql = N'CREATE FUNCTION ...';
    EXEC sp_executesql @sql;
END

또는 당신은 말할 수 있습니다 :

BEGIN TRY
    DROP FUNCTION dbo.fn_myfunc;
END TRY
BEGIN CATCH
    PRINT 'Function did not exist.';
END CATCH
GO
CREATE FUNCTION...

아니면 그냥 말할 수 있습니다 :

DROP FUNCTION dbo.fn_myfunc;
GO
CREATE FUNCTION...

(여기에 함수가 존재하지 않으면 오류 메시지가 표시되지만 스크립트는 다음 GO부터 계속되므로 드롭이 작동했는지 여부에 관계없이 함수는 여전히 (재) 생성됩니다.)

함수를 삭제하고 다시 작성하면 권한 및 잠재적으로 종속 정보도 손실됩니다.


1
키워드가 없습니다 $$ CREATE OR REPLACE $$? 동정.
zinking

@zinking 아니오, 그러나 향후 버전에서. 투표 / 의견을
Aaron Bertrand

1
@AaronBertrand 투표에 대한 좋은 생각이지만 링크가 끊어졌습니다
푸르스름한

@bluish 죄송합니다. 3 년 전 링크를 게시했을 때부터 항목을 삭제했습니다. connect.microsoft.com/SQLServer/feedback/details/344991/… 또는 connect.microsoft.com/SQLServer/feedback / details / 351217 /…
Aaron Bertrand


1

오류는 설명이 필요 없습니다. 그것을 고치는 데에는 몇 가지 방법이 있습니다.

  1. GO의사 키워드 및 DROP/ / CREATE객체를 사용하여 Management Studio에서 스크립트를 다른 배치로 분리하십시오 . (키워드 자체는 Management Studio 옵션에서 변경할 수 있지만 실제로 설정이므로 그대로 두는 것이 좋습니다.)

    스크립트 (또는 스크립트의 선택된 부분)를 실행할 때 Management Studio는 GOs 간에 각 스크립트 청크를 분리 하고 순차적으로 파트를 SQL Server에 개별 배치로 보냅니다.

  2. 동적 SQL을 사용하여 다른 배치 내에서 별도의 배치를 보냅니다.

    이 방법은 스크립트가 외부 기능에 의존하여 올바르게 실행되지 않기 때문에 선호되는 방법입니다. 예를 들어, 응용 프로그램에 데이터베이스 업데이트 프로그램이있는 경우 일반적으로 말하면 스크립트 파일을로드 한 다음 대상 서버에서 실행합니다. Management Studio에서와 같이 배치를 분리하기위한 로직을 추가하거나 (참고 : 위험으로 가득 차기) 전체 스크립트를 단일 배치로 성공적으로 실행할 수 있는 방식으로 스크립트를 작성해야합니다 .

    다른 답변에서 언급 했듯이이 CREATE방법 (또는 DROP/ CREATE등 의 다른 조합)을 사용하여 테스트 / 를 수행 할 수 있습니다 . 내가 선호하는 것은 객체가 존재하지 않으면 스텁 객체를 만든 다음 ALTER <object>실제로 생성 또는 변경을 수행하는 데 사용 하는 것입니다. 이 방법은 권한이나 확장 속성과 같은 종속성을 제거하지 않으며 단일 문에서 CREATE/ 를 수행하기 위해 오류가 발생하기 쉬운 논리를 복사 / 붙여 넣을 필요가 없습니다 ALTER.

    다음은 스칼라 함수를 만들거나 변경하는 데 사용하는 템플릿입니다. 독자가 이것을 다른 유형의 객체 (저장된 proc, 트리거 등)에 적용하는 연습으로 남겨 두겠습니다.

IF NOT EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[<schema>].[<function name>]') AND type IN ('FN', 'FS'))
    EXEC sp_executesql N'CREATE FUNCTION [<schema name>].[<function name>] (@a int) RETURNS int AS BEGIN /* Stub */ RETURN @a END'

EXEC sp_executesql N'
ALTER FUNCTION [<schema name>].[<function name>]
/* ... */
'

옵션 1은 어떻게 작동합니까? GO실제로 추가 하면 IF아무데도 이끌지 않으므로 스크립트가 중단 됩니다.
Aaron Bertrand

@Aaron : 나는 DROP/ CREATE시나리오를 생각하고 있었다 -편집했다. 감사.
Jon Seigel 2016 년

1

객체가 존재하는지 확인하는 옵션이 있으며 database그렇지 않은 경우 생성 할 수 있습니다.

IF OBJECT_ID('new_function', 'FN') IS NULL
BEGIN
  EXEC('CREATE FUNCTION new_function() RETURNS INT AS BEGIN RETURN 1 END');
END;
go

ALTER FUNCTION new_function() RETURNS INT AS
BEGIN

...
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.