SQL에서 중앙값(MEDIAN) 계산
소개
SQL에서 중앙값을 산출하는 방법은, 사용하기 때문에 성능이 매우 나쁜 것 같습니다.
거기서, 퍼포먼스를 개선하는 방법으로서, 건수의 집계를 실시하고 나서 자기 결합하는 방법을 생각해 왔으므로 소개합니다.
 해설
간단한 샘플 데이터로 짝수 짝수 건수와 홀수 홀수 건 데이터를 준비합니다.
 짝수 데이터
값
1
1
2
3
 홀수건 데이터
값
1
1
2
3
3
 (1) 우선 값별로 데이터 건수를 집계한다
SELECT
  値
, COUNT(*) AS 件数
FROM 偶数件データ
GROUP BY 値
전술 한 테이블은 뷰, 임시 테이블 또는 서브 쿼리로서 후속 SQL에서 집계 데이터로 표현된다.
 짝수 개의 데이터 실행 결과
값
건수
1
2
2
1
3
1
 홀수건 데이터 실행 결과
값
건수
1
2
2
1
3
2
 (2) 건수의 누적 계산
SELECT
  Z.値
, Z.件数
, SUM(A.件数) AS 累積件数
FROM 集計データ AS Z,
     集計データ AS A
WHERE Z.値 >= A.値
GROUP BY
  Z.値
, Z.件数
 짝수 개의 데이터 실행 결과
값
건수
누적 건수
1
2
2
2
1
3
3
1
4
 홀수건 데이터 실행 결과
값
건수
누적 건수
1
2
2
2
1
3
3
2
5
 (3) 누적 전 건수(해당 레코드의 건수를 가산하기 전의 건수)와 중간 건수(전체의 절반에 해당하는 건수)를 합쳐서 표시한다
SELECT
  Z.値
, Z.件数
, SUM(A.件数) - Z.件数 AS 累積前件数
, SUM(A.件数) AS 累積件数
, (SELECT SUM(件数)/2 FROM 集計データ) AS 中間件数
FROM 集計データ AS Z,
     集計データ AS A
WHERE Z.値 >= A.値
GROUP BY
  Z.値
, Z.件数
 짝수 개의 데이터 실행 결과
값
건수
누적 전 건수
누적 건수
중간 건수
1
2
0
2
2
2
1
2
3
2
3
1
3
4
2
 홀수건 데이터 실행 결과
값
건수
누적 전 건수
누적 건수
중간 건수
1
2
0
2
2.5
2
1
2
3
2.5
3
2
3
5
2.5
 (4) 누적 전 건수 ≤ 중간 건수 ≤ 누적 건수를 만족하는 레코드를 추출한다
SELECT *
FROM 
	(SELECT
	  Z.値
	, Z.件数
	, SUM(A.件数) - Z.件数 AS 累積前件数
	, SUM(A.件数) AS 累積件数
	, (SELECT SUM(件数)/2 FROM 集計データ) AS 中間件数
	FROM 集計データ AS Z,
	     集計データ AS A
	WHERE Z.値 >= A.値
	GROUP BY
	  Z.値
	, Z.件数) AS SUB
WHERE 中間件数 BETWEEN 累積前件数 AND 累積件数
 짝수 개의 데이터 실행 결과
값
건수
누적 전 건수
누적 건수
중간 건수
1
2
0
2
2
2
1
2
3
2
※1레코드 또는 2레코드가 대상이 됩니다.
 홀수건 데이터 실행 결과
값
건수
누적 전 건수
누적 건수
중간 건수
2
1
2
3
2.5
※반드시 1레코드만이 대상이 됩니다.
 (5) (4)에서 추출한 레코드의 값의 평균을 산출한다.
SELECT AVG(値) AS 中央値
FROM 
    (SELECT
      Z.値
    , Z.件数
    , SUM(A.件数) AS 累積件数
    , (SELECT SUM(件数) FROM 集計データ) AS 総件数
    FROM 集計データ AS Z,
         集計データ AS A
    WHERE Z.値 >= A.値
    GROUP BY
      Z.値
    , Z.件数) AS SUB
WHERE 総件数/2 BETWEEN 累積件数 - 件数  AND 累積件数
※일부 표현을 깨끗이 하기 위해서, 계산 순서를 바꾸고 있습니다.
 짝수 개의 데이터 실행 결과
중앙값
1.5
 홀수건 데이터 실행 결과
중앙값
2
 여기 기사의 질문 4의 실행 결과
(3)의 실행 결과가 이하와 같고, 노란색의 2 레코드가 (4)의 추출 대상이 되고, 결과는 220000과 235000의 평균으로 227500이 됩니다
 여기
 참고로 분석 함수를 사용한 SQL의 예는 다음과 같습니다.
WITH SUB AS (
  SELECT
    値
  , 件数
  , SUM(件数) OVER( ORDER BY 値) AS 累積件数
  , SUM(件数) OVER() AS 総件数
  FROM 集計データ
)
SELECT AVG(値) AS 中央値
FROM SUB
WHERE 総件数/2 BETWEEN 累積件数 - 件数 AND 累積件数
 잘 생각하면, 분석 함수를 사용한 경우는 자기 결합이 불필요하게 되므로, 집계 데이터를 일부러 사용할 필요도 없기 때문에 이하의 내용으로 가능합니다
WITH SUB AS (
  SELECT
    値
  , ROW_NUMBER() OVER (ORDER BY 値) AS 連番
  , COUNT(*) OVER () AS 総件数
  FROM 元テーブル
)
SELECT AVG(値) AS 中央値
FROM SUB
WHERE 総件数/2 BETWEEN 連番 - 1 AND 連番
                
                    
        
    
    
    
    
    
                
                
                
                
                    
                        
                            
                            
                            Reference
                            
                            이 문제에 관하여(SQL에서 중앙값(MEDIAN) 계산), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
                                
                                https://qiita.com/takahasinaoki/items/1dd99f69eaef677b8c14
                            
                            
                            
                                텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                            
                            
                                
                                
                                 우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)
                            
                            
                        
                    
                
                
                
            
간단한 샘플 데이터로 짝수 짝수 건수와 홀수 홀수 건 데이터를 준비합니다.
짝수 데이터
값
1
1
2
3
홀수건 데이터
값
1
1
2
3
3
(1) 우선 값별로 데이터 건수를 집계한다
SELECT
  値
, COUNT(*) AS 件数
FROM 偶数件データ
GROUP BY 値
짝수 개의 데이터 실행 결과
값
건수
1
2
2
1
3
1
홀수건 데이터 실행 결과
값
건수
1
2
2
1
3
2
(2) 건수의 누적 계산
SELECT
  Z.値
, Z.件数
, SUM(A.件数) AS 累積件数
FROM 集計データ AS Z,
     集計データ AS A
WHERE Z.値 >= A.値
GROUP BY
  Z.値
, Z.件数
짝수 개의 데이터 실행 결과
값
건수
누적 건수
1
2
2
2
1
3
3
1
4
홀수건 데이터 실행 결과
값
건수
누적 건수
1
2
2
2
1
3
3
2
5
(3) 누적 전 건수(해당 레코드의 건수를 가산하기 전의 건수)와 중간 건수(전체의 절반에 해당하는 건수)를 합쳐서 표시한다
SELECT
  Z.値
, Z.件数
, SUM(A.件数) - Z.件数 AS 累積前件数
, SUM(A.件数) AS 累積件数
, (SELECT SUM(件数)/2 FROM 集計データ) AS 中間件数
FROM 集計データ AS Z,
     集計データ AS A
WHERE Z.値 >= A.値
GROUP BY
  Z.値
, Z.件数
짝수 개의 데이터 실행 결과
값
건수
누적 전 건수
누적 건수
중간 건수
1
2
0
2
2
2
1
2
3
2
3
1
3
4
2
홀수건 데이터 실행 결과
값
건수
누적 전 건수
누적 건수
중간 건수
1
2
0
2
2.5
2
1
2
3
2.5
3
2
3
5
2.5
(4) 누적 전 건수 ≤ 중간 건수 ≤ 누적 건수를 만족하는 레코드를 추출한다
SELECT *
FROM 
	(SELECT
	  Z.値
	, Z.件数
	, SUM(A.件数) - Z.件数 AS 累積前件数
	, SUM(A.件数) AS 累積件数
	, (SELECT SUM(件数)/2 FROM 集計データ) AS 中間件数
	FROM 集計データ AS Z,
	     集計データ AS A
	WHERE Z.値 >= A.値
	GROUP BY
	  Z.値
	, Z.件数) AS SUB
WHERE 中間件数 BETWEEN 累積前件数 AND 累積件数
짝수 개의 데이터 실행 결과
값
건수
누적 전 건수
누적 건수
중간 건수
1
2
0
2
2
2
1
2
3
2
※1레코드 또는 2레코드가 대상이 됩니다.
홀수건 데이터 실행 결과
값
건수
누적 전 건수
누적 건수
중간 건수
2
1
2
3
2.5
※반드시 1레코드만이 대상이 됩니다.
(5) (4)에서 추출한 레코드의 값의 평균을 산출한다.
SELECT AVG(値) AS 中央値
FROM 
    (SELECT
      Z.値
    , Z.件数
    , SUM(A.件数) AS 累積件数
    , (SELECT SUM(件数) FROM 集計データ) AS 総件数
    FROM 集計データ AS Z,
         集計データ AS A
    WHERE Z.値 >= A.値
    GROUP BY
      Z.値
    , Z.件数) AS SUB
WHERE 総件数/2 BETWEEN 累積件数 - 件数  AND 累積件数
짝수 개의 데이터 실행 결과
중앙값
1.5
홀수건 데이터 실행 결과
중앙값
2
여기 기사의 질문 4의 실행 결과
(3)의 실행 결과가 이하와 같고, 노란색의 2 레코드가 (4)의 추출 대상이 되고, 결과는 220000과 235000의 평균으로 227500이 됩니다
여기
참고로 분석 함수를 사용한 SQL의 예는 다음과 같습니다.
WITH SUB AS (
  SELECT
    値
  , 件数
  , SUM(件数) OVER( ORDER BY 値) AS 累積件数
  , SUM(件数) OVER() AS 総件数
  FROM 集計データ
)
SELECT AVG(値) AS 中央値
FROM SUB
WHERE 総件数/2 BETWEEN 累積件数 - 件数 AND 累積件数
잘 생각하면, 분석 함수를 사용한 경우는 자기 결합이 불필요하게 되므로, 집계 데이터를 일부러 사용할 필요도 없기 때문에 이하의 내용으로 가능합니다
WITH SUB AS (
  SELECT
    値
  , ROW_NUMBER() OVER (ORDER BY 値) AS 連番
  , COUNT(*) OVER () AS 総件数
  FROM 元テーブル
)
SELECT AVG(値) AS 中央値
FROM SUB
WHERE 総件数/2 BETWEEN 連番 - 1 AND 連番
Reference
이 문제에 관하여(SQL에서 중앙값(MEDIAN) 계산), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/takahasinaoki/items/1dd99f69eaef677b8c14텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
                                
                                
                                
                                
                                
                                우수한 개발자 콘텐츠 발견에 전념
                                (Collection and Share based on the CC Protocol.)