반응형


김종열

MS SQL Server MVP



 

정말 오랜만에 글을 올리네요. ^^

쿼리를 다루시다가 보면 이전행의 데이터를 가져오는 부분을 짜는 일이 있을 겁니다.
그 하나의 데이터를 가져오기 위해 다시 join을 사용하면서 이를 지원해주는 함수가 없을까 생각해봤을 겁니다. oracle에는 lag(), lead()라는 window Function을 제공해줍니다.

역시 이런 함수를 mssql에서 다룰 수 있도록 해달라는군요..
이런 메시지를 받으면 고민하고 시도를 해봐야 겠다는 맘이 생기지요..


using
System;

using System.Data;

using System.Data.SqlClient;

using System.Data.SqlTypes;

using Microsoft.SqlServer.Server;

using System.Collections.Generic;

 

public partial class UserDefinedFunctions

{

    public readonly static Dictionary<string, List<object>> _dicMemory = new Dictionary<string, List<object>>();

   

    [Microsoft.SqlServer.Server.SqlFunction]

    public static SqlString Udf_Lag(object objValue, int rowNo, int key, string guid)

    {

        //Return 변수 선언

        string retValue = string.Empty;

 

        //Guid 존재 하지 않을 경우 새로운 시작

        if (_dicMemory.ContainsKey(guid) == false)

        {

            //Dictionary guid 키로 하여 새로운 List 생성 한다.

            _dicMemory.Add(guid, new List<object>());

        }

 

        //Guid 따른 저장 List 값을 가져 온다.

        List<object> tempList = _dicMemory[guid];

 

        //현재 저장된 리스트의 개수

        int valueCount = tempList.Count;

 

        if (valueCount - rowNo -1  < 0)

        {

            //부모 값이 없는 경우

            retValue = string.Empty;

        }

        else

        {

            //부모의 값이 있는 경우 반환 값을 넘긴다.

            retValue = Convert.ToString(tempList[valueCount - rowNo - 1]);

        }

 

        tempList.Add(objValue);

 

        //key -> 1 시작

        //key -> 0 진행중

        //key -> -1 종료

        if (key == -1)

        {

            //종료일 경우 메모리에서 값을 삭제 한다.

            _dicMemory.Remove(guid);

        }

 

        return retValue;

    }

 

};

 


만들며 데이터가 들어온 순서를 메모리에 담기때문에 동시에 두곳에서 실행을 하면 메모리에서
중복이 일어나 제대로 된 결과를 얻을 수 없게 됩니다. 해서 newid를 이용해서 고유한 스티링을 이용해
메모리 충돌이 일어나지 않게 변수를 생성하여 그곳에 데이터를 담아 각자의 session에 대한
제대로 된 결과를 제공해주자는 것입니다.

물론 메모리에 들어갔으므로 실행을 마쳤다면 종료를 시켜줘야 하는데 그게 endbit가 필요한 이유입니다.

여튼 실행의 예시는 다음과 같습니다.


CREATE TABLE tempdb.dbo.t (a INT IDENTITY(1,1))

GO

 

 

INSERT INTO tempdb.dbo.t DEFAULT VALUES

GO 40000

 

 

 

DECLARE @endBit INT = 0

DECLARE @guid NVARCHAR(50) = NEWID()

 

SELECT @endBit = COUNT(*) FROM tempdb.dbo.t

 

/*

udf_lag(데이터열, 몇행앞으로(1, 2, 3.), 시작중간끝(1,0,-1), guid)

 

*/

SELECT

       a

       , dbo.udf_lag(a, 3, CASE ROW_NUMBER() OVER (ORDER BY a) 

                                              WHEN 1 THEN 1

                                              WHEN @endbit THEN -1

                                              ELSE 0 END , @guid)                    

FROM

       tempdb.dbo.t

첨부 : Udf_Lag.cs
        udf_lag.sql

반응형

'연구개발 > CLR' 카테고리의 다른 글

CLR - Windows Event Log  (0) 2011.08.27
CLR - 누적합 구하기  (0) 2011.08.27
WMI 객체를 쿼리로 읽어오기  (0) 2010.08.10
파일리스트 불러오기  (0) 2009.06.22
CLR-server와 통신하기  (1) 2009.06.22

+ Recent posts