2011-10-07 7 views
1

나는 간단한 MEDIAN 계산 기능이 있습니다GROUP BY에서 사용자 정의 집계 함수 사용?

IF OBJECT_ID(N'COMPUTEMEDIAN', N'FN') IS NOT NULL 
    DROP FUNCTION dbo.COMPUTEMEDIAN; 
GO 
CREATE FUNCTION dbo.COMPUTEMEDIAN(@VALUES NVARCHAR(MAX)) 
RETURNS DECIMAL 
WITH EXECUTE AS CALLER 
AS 
BEGIN 
    DECLARE @SQL NVARCHAR(MAX) 
    DECLARE @MEDIAN DECIMAL 
    SET @MEDIAN = 0.0; 

    DECLARE @MEDIAN_TEMP TABLE (RawValue DECIMAL); 

    -- This is the Killer! 
    INSERT INTO @MEDIAN_TEMP 
    SELECT s FROM master.dbo.Split(',', @VALUES) OPTION(MAXRECURSION 0) 

    SELECT @MEDIAN = 
    (
    (SELECT MAX(RawValue) FROM 
     (SELECT TOP 50 PERCENT RawValue FROM @MEDIAN_TEMP ORDER BY RawValue) AS BottomHalf) 
    + 
    (SELECT MIN(RawValue) FROM 
     (SELECT TOP 50 PERCENT RawValue FROM @MEDIAN_TEMP ORDER BY RawValue DESC) AS TopHalf) 
    )/2 

    --PRINT @SQL 
    RETURN @MEDIAN; 
END; 
GO 

는하지만, 내 표는 다음과 같은 형식으로되어 있습니다 GROUP BY를 사용하여이 테이블에 MEDIAN 함수를 호출하는 가장 좋은 방법은 무엇

CREATE TABLE #TEMP (GroupName VARCHAR(MAX), Value DECIMAL) 
INSERT INTO #TEMP VALUES ('A', 1.0) 
INSERT INTO #TEMP VALUES ('A', 2.0) 
INSERT INTO #TEMP VALUES ('A', 3.0) 
INSERT INTO #TEMP VALUES ('A', 4.0) 
INSERT INTO #TEMP VALUES ('B', 10.0) 
INSERT INTO #TEMP VALUES ('B', 11.0) 
INSERT INTO #TEMP VALUES ('B', 12.0) 

SELECT * FROM #TEMP 

DROP TABLE #TEMP 

id 열에? 그래서, 나는 이런 식으로 뭔가를 찾고 있어요 :

SELECT id, COMPUTEMEDIAN(Values) 
FROM #TEMP 
GROUP BY id 

내 현재의 접근 방식은 함수에 전달 후 큰 문자열로 GROUP BY 조작으로 인한 모든 값을 결합 XMLPATH을 사용하는 것입니다 그러나 이것은 문자열 분할 작업을 포함한다 큰 문자열의 경우 이것은 모든 것을 느리게 만듭니다. 어떤 제안?

답변

1

편집 :이 (30,000 값)

흠 ... 그냥 this 건너 왔어요 그래서 다음과 같은 대용량 데이터베이스에 아주 아주 잘 작동 확인할 수 있습니다 완벽하게 잘 작동하지만 비싸다는 것이 확실하지 않습니다.

SELECT 
    GroupName, 
    AVG(Value) 
FROM 
(
    SELECT 
     GroupName, 
     cast(Value as decimal(5,2)) Value, 
     ROW_NUMBER() OVER (
     PARTITION BY GroupName 
     ORDER BY Value ASC) AS RowAsc, 
     ROW_NUMBER() OVER (
     PARTITION BY GroupName 
     ORDER BY Value DESC) AS RowDesc 
    FROM #TEMP SOH 
) x 
WHERE 
    RowAsc IN (RowDesc, RowDesc - 1, RowDesc + 1) 
GROUP BY GroupName 
ORDER BY GroupName; 
1

SQL Server 2008을 사용하고 있으므로 집계 함수를 CLR 함수로 작성하는 것이 좋습니다.

http://msdn.microsoft.com/en-us/library/91e6taax(v=vs.80).aspx

또한, 사람들은 전에이 질문을했다. 아마도 그들의 대답 도움이 될 것입니다

Function to Calculate Median in Sql Server

+0

예. 나는 그것을 보았지만 특별한 특권이 필요하지 않은가? 매우 제한된 환경에서이 스크립트를 실행하므로 CLR이 나를위한 옵션인지 확실하지 않습니다. – Legend

+0

올바른, CLR 함수를로드 할 수있는 데 필요한 특수 사용 권한이 있습니다 : "CREATE AGGREGATE 권한이 필요하며 EXTERNAL NAME 절에 지정된 어셈블리에 대한 REFERENCES 권한이 필요합니다." http://msdn.microsoft.com/en-us/library/ms182741.aspx –

+0

예. 그것은 내 관심사였다. 하지만 +1 시간. 고맙습니다. – Legend

1

사용자 정의 함수를 사용할 필요가 없습니다! 다음과 같이 할 수 있습니다 :

CREATE TABLE #TEMP (id VARCHAR(MAX), Value DECIMAL) 

INSERT INTO #TEMP VALUES('A', 1.0) 

INSERT INTO #TEMP VALUES('A', 2.0) 
INSERT INTO #TEMP VALUES('A', 3.0) 
INSERT INTO #TEMP VALUES('A', 4.0) 
INSERT INTO #TEMP VALUES('B', 10.0) 
INSERT INTO #TEMP VALUES('B', 11.0) 
INSERT INTO #TEMP VALUES('B', 12.0) 

SELECT 
    (SELECT TOP 1 Value 
     FROM (SELECT TOP(calcs.medianIndex) Value 
       FROM #temp 
       WHERE #temp.ID = calcs.ID ORDER BY Value ASC) AS subSet 
     ORDER BY subSet.Value DESC), ID 
FROM 
(SELECT 
    CASE WHEN count(*) % 2 = 1 THEN count(*)/2 + 1 
     ELSE count(*)/2 
    END AS medianIndex, 
ID 
FROM #TEMP 
GROUP BY ID) AS calcs 

DROP TABLE #TEMP 

짝수 개의 레코드가있을 때 동작을 다시 확인해야 할 수도 있습니다.

편집 : Median 함수에서 작업을 검토 한 결과, 기본적으로 방금 함수가 사용자의 작업을 일반 쿼리로 이동 시켰습니다. 그래서 ... 왜 사용자 정의 함수의 중간 계산을해야합니까? 그렇게 많이 곤란한 것 같습니다. .

+0

+1 사실, 당신 말이 맞습니다. 나는 그것이 더 복잡한 집계 함수를 가지고있을 것이라고 생각하고 있었지만 분명히 나는 ​​이것을 하나없이 끝낼 수있다. 그럼에도 불구하고 당신의 노력에 감사드립니다. – Legend

관련 문제