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


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.