스크립트 또는 저장 프로 시저에서 일회용 함수를 만들 수 있습니까?


109

SQL Server 2005에는 SQL 스크립트 또는 저장 프로 시저 내에 선언 된 일회성 또는 로컬 함수의 개념이 있습니까? 내가 작성중인 스크립트의 복잡성을 추상화하고 싶지만 함수를 선언 할 수 있어야합니다.

그냥 궁금해.


함수없이 원하는 작업을 수행하는 더 좋은 방법이있을 것입니다. 함수로 바꾸고 싶은 코드의 스 니펫을 게시해야할까요?
— DForck42

매번 다른 함수를 동적으로 생성하고 있습니까? 기능이 항상 동일하다면 데이터베이스에 그대로 두십시오
— KM.

1
쿼리를 더 읽기 쉽게하는 방법으로 시도했습니다. 거대한 쿼리를 생성한다는 아이디어는 유지 관리를 어렵게 만듭니다.
— Jp_

답변:


65

CREATE Function스크립트 시작 부분과 DROP Function끝 부분에 전화를 걸 수 있습니다 .


6
나는 이것을 제안하려고했다. 스크립트가 완료되도록주의하십시오. 중단 되더라도 DB에 여전히 기능이 있습니다.
— chocojosh 2009-06-11

6
각 실행 전에 IF EXISTS 확인을 수행하고 발견 된 항목이 있으면 삭제할 수 있습니다.
— Adrian Godong

7
@chocojosh, 트랜잭션으로 포장하면 괜찮을 것입니다. 트랜잭션이 폭탄을 터뜨리면 함수는 데이터베이스에 없어야합니다.
— Jeff LaFay 2011

12
@JoelCoehoorn : 여전히 쓰기 권한이 필요합니다.
— user2284570

2
이것은 함수 내부에서 작동하지 않습니다. 함수 내부의 임시 함수는 허용되지 않습니다. 참조 : technet.microsoft.com/en-us/library/ms191320.aspx#Restrictions
— Daniel Neel

95

다음과 같은 임시 저장 프로 시저를 만들 수 있습니다.

create procedure #mytemp as
begin
   select getdate() into #mytemptable;
end

SQL 스크립트에 있지만 함수는 아닙니다. 당신은 임시 테이블에 결과를 저장하는 proc을 가질 수 있으며, 그 정보를 나중에 스크립트에서 사용할 수 있습니다 ..


7
이것이 답이되어야합니다. 이는 연결 범위가 임시 (단일 #) 인 경우에만 진정한 일회용이며 SQL 사용자 제한을 피할 수있는 이점이 있습니다.
— Todd

그러면 어떻게 사용됩니까? select into 표현식에 사용 된 프로 시저 이름의 오타 아닌가요?
— jgomo3 2013 년

나는 내가 제거 할 때 예를 들어 저장 프로 시저의 결과를 얻을 수있어 BEGIN키워드를, 그리고 교체 END와 키워드를 GO.
— Joseph Dykstra

OP는 임시 FUNCTION을 요청했으며 적어도 SQL Server 2012에서는 함수에 # 구문을 허용하지 않습니다. 절차 만.
— Erk

이는 스크립트 내에서 작동하지 않으며 여전히 권한이 필요할 수 있습니다. 반복적 인 세그먼트를 피하기 위해 SQL에있는 유일한 옵션은 WITH 문입니다.
— alex.peter

25

공통 테이블 표현식 을 사용하면 select, insert, update 및 delete 문의 범위 내에서만 지속되는 본질적으로보기를 정의 할 수 있습니다. 무엇을해야하는지에 따라 매우 유용 할 수 있습니다.


5
이것은 정답으로 받아 들여 져야합니다. 허용되는 답변은 스레드로부터 안전하지 않습니다.
— kalyan 2014 년

11
무엇을 하려는지에 따라 다릅니다. 데이터 시더를 작성 중이고 MERGE INTO의 10 줄을 30 번 반복하고 싶지 않기 때문에이 질문을 찾았습니다. 나는 스레드 세이프에 대해 신경 쓰지 않으며 CTE는 나를 위해 작동하지 않을 것입니다.
— solipsicle

16
나는이 대답과 그것이 정답이라는 주장, 질문이 temp TABLE이 아닌 temp FUNCTION을 찾고 있다는 것을 놓친다고 생각합니다. 내가 뭔가를 놓치고 있지 않는 한 (흔하지 않은) CTE는 임시 테이블과 비슷합니다.
— JD Long

8
함수는 인수를받을 수 있지만 CTE는받을 수 없습니다.
— Răzvan Flavius ​​Panda

4
CTE와 임시 저장 프로 시저 사이에는 많은 차이가 있습니다 (여기서는 IMO에서 정답입니다). 우선 CTE는 단일 문에 대해서만 존재하는 반면 임시 변수는 스크립트 전체에서 사용할 수 있습니다. 다른 차이점은 다음과 같습니다. (1) CTE는 SP와 동일한 논리를 수용 할 수 없으며, (2) CTE는 변수를 허용 할 수 없습니다. CTE는 구문에 사용하기 위해 중첩 된 테이블 식을보다 쉽게 ​​작성할 수 있도록하는 구문 적 설탕 일뿐입니다. 그럼에도 불구하고 경고를 인식하지 못하면 성능 측면에서 위험 할 수 있습니다.
— Lopsided

12

동적 SQL을 제안하는 것에 대해 비판을받을 수 있다는 것을 알고 있지만 때로는 좋은 솔루션입니다. 이를 고려하기 전에 보안 의미를 이해했는지 확인하십시오.

DECLARE @add_a_b_func nvarchar(4000) = N'SELECT @c = @a + @b;';
DECLARE @add_a_b_parm nvarchar(500) = N'@a int, @b int, @c int OUTPUT';

DECLARE @result int;
EXEC sp_executesql @add_a_b_func, @add_a_b_parm, 2, 3, @c = @result OUTPUT;
PRINT CONVERT(varchar, @result); -- prints '5'

4

스크립트에는 더 많은 옵션과 합리적인 분해에 대한 더 나은 샷이 있습니다. SQLCMD 모드 (조회 메뉴-> SQLCMD 모드), 특히 : setvar 및 : r 명령을 살펴보십시오.

저장 프로 시저 내에서 옵션은 매우 제한적입니다. 프로 시저 본문을 사용하여 직접 함수를 정의 할 수 없습니다. 최선의 방법은 다음과 같이 동적 SQL을 사용하는 것입니다.

create proc DoStuff
as begin

  declare @sql nvarchar(max)

  /*
  define function here, within a string
  note the underscore prefix, a good convention for user-defined temporary objects
  */
  set @sql = '
    create function dbo._object_name_twopart (@object_id int)
    returns nvarchar(517) as
    begin
      return 
        quotename(object_schema_name(@object_id))+N''.''+
        quotename(object_name(@object_id))
    end
  '

  /*
  create the function by executing the string, with a conditional object drop upfront
  */
  if object_id('dbo._object_name_twopart') is not null drop function _object_name_twopart
  exec (@sql)

  /*
  use the function in a query
  */
  select object_id, dbo._object_name_twopart(object_id) 
  from sys.objects
  where type = 'U'

  /*
  clean up
  */
  drop function _object_name_twopart

end
go

이러한 것이 존재한다면 이것은 전역 임시 함수에 가깝습니다. 다른 사용자는 여전히 볼 수 있습니다. 연결의 @@ SPID를 추가하여 이름을 고유하게 만들 수 있지만 나머지 절차에서도 동적 SQL을 사용해야합니다.


3

아래는 과거에 MS SQL에서 Scalar UDF에 대한 필요성을 달성하기 위해 사용한 것입니다.

IF OBJECT_ID('tempdb..##fn_Divide') IS NOT NULL DROP PROCEDURE ##fn_Divide
GO
CREATE PROCEDURE ##fn_Divide (@Numerator Real, @Denominator Real) AS
BEGIN
    SELECT Division =
        CASE WHEN @Denominator != 0 AND @Denominator is NOT NULL AND  @Numerator != 0 AND @Numerator is NOT NULL THEN
        @Numerator / @Denominator
        ELSE
            0
        END
    RETURN
END
GO

Exec ##fn_Divide 6,4

PROCEDURE에 전역 변수를 사용하는이 접근 방식을 사용하면 스크립트뿐만 아니라 동적 SQL 요구 사항에서도 함수를 사용할 수 있습니다.

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