석차 구하기
조건.
TABLE : TEST20
EMPID POINT
---------- ----------
A00000 49
A00600 56
A01000 47
A01002 34
A01400 29
A02002 22
A04003 18
A09100 14
A09200 13
A10000 39
A10002 20
A10600 46
A11000 37
A11002 24
A11400 19
A12002 12
A14003 28
A19100 24
A19200 23
A90002 10
위와같이 TEST20 TABLE에 사번별 점수가 들어있다.
문제.
위의 DATA를 이용하여 석차를 구하여 순위별로
보여주고싶다.
석차를 구하는 방식은 일반적으로 우리가 알고 있는 것과 동일하다.
즉, 동일점수가 2명이상이면 동일점수는 같은 순위가 부여되고
다음 점수는 그만큼 건너뛴 순위가 부여되어야 한다.
먼저 답을 보면 다음과 같다.
EMPID 순위
---------- ----------
A00600 1
A00000 2
A01000 3
A10600 4
A10000 5
A11000 6
A01002 7
A01400 8
A14003 9
A11002 10
A19100 10
A19200 12
A02002 13
A10002 14
A11400 15
A04003 16
A09100 17
A09200 18
A12002 19
A90002 20
생각.
어렵게 생각하면 어려워지고 쉽게 생각하면 쉬운 문제다.
문제를 해결하는 방법은 모든 문제가 그렇듯이 하나 이상이
나올 수 있다.
물론 방법에 따라 결과가 나오는 시간이 다를수 는 있다.
엿보기1.가장쉽게 생각할 수 있는것은 각 사번별로 자기보다 점수가
큰 사람의 숫자를 세어서 거기에 1을 더하는 방식이다.
주의할 것은 자기점수보다 크거나 같은 사람의 숫자가
자기의 석차가 아니라는 것이다.
자기 점수와 동일인이 여러명 있을수 있기 때문이다.
방법은 간단하다.
SELF JOIN을 이용하되 한쪽을 자기보다 큰점수로 비교하고
순위 1인 사람을 위하여 (+) 기호를 붙여주면된다.
엿보기2.다음 방법도 같은 원리다.
큰점수부터 순위가 붙어야 하므로 먼저 1을 각 점수별로
나누어서 각 점수별로 GROUP을 만든다.
엿보기3.다음은 역시 같은방식으로 인원수를 구해서 1을 빼준다.
그리고 두개의 DATASET을 1/점수로 부등호 JOIN을 걸어준다.
JOIN된 결과를 1/점수로 GROUP 지으면 1/점수대별로
각각 자신의 GROUP 지어진 순위와 자신보다 상위순위중
동일 점수로 인해 중복된 인원수를 구할수 있다.
엿보기4.이제 TABLE을 한번 더 읽어서 1/점수로 다시 JOIN을 걸고
EMPID를 가져오고,순위와 중복인원을 더해주면 된다.
두번째 방법은 말로만 이해하기에 약간의 어려움이
있을 듯하다
이해가 안가면 해법을 통해 이해할 수 있는 길을 찾아보자.
해법.엿보기를 통해 두가지 방법이 제시되었는데 어떤방법이 더 빠를지
한번 생각을 해보고 해법을 접하기 바란다.
두가지 모두가 부등호 JOIN이다.
앞의 주제에서도 다뤘듯이 SELF JOIN이 부등호로써 연결될때는
DATA의 숫자가 증가함에 따라 RESPONSE TIME이 지수함수적으로
증가한다는 것을 알고있다.
단계1.첫번째 단계에서는 엿보기1에서 방식을 SQL문으로 옮겨보겠다.
SELECT A.EMPID,
COUNT(B.EMPID ) + 1
FROM TEST20 A,
TEST20 B
WHERE B.POINT(+) > A.POINT
GROUP BY A.EMPID
ORDER BY COUNT(B.EMPID)
엿보기1을 통해 충분한 설명이 있었으므로 이해하기에 어려움이
없으리라 본다.
단계2.각 점수대별 중복인원수를 구하는 방법은 다음과 같다.
SELECT 1/POINT POINT_D,COUNT(*) - 1 CNT
FROM TEST20
GROUP BY 1/POINT
단계3.위의 DATASET을 다시 점수대별로 부등호 JOIN을 거는 방법은
다음과 같다.
SELECT A.POINT_D POINT_D,
SUM(B.CNT) ADV
FROM (SELECT 1/POINT POINT_D CNT
FROM TEST20
GROUP BY 1/POINT
) A,
(SELECT 1/POINT POINT_D,COUNT(*) - 1 CNT
FROM TEST20
GROUP BY 1/POINT
) B
WHERE B.POINT_D(+) < A.POINT_D
GROUP BY A.POINT_D
점수대별 중복인원수 구하는 DATASET이 B 이다.
단계4.위의 결과를 이용해 점수대별 순위와 순위에 더해질
중복인원수를 구하려면
다음과 같이 DATASET을 FROM절로 넣고 SELECT절만 추가한다.
SELECT POINT_D,ROWNUM GRAD,ADV
단계5.위의 결과 다시 자기 TABLE과 부등호로 연결하여 사번과함께
순위 + 중복인원을 읽어오면된다.
최종 SQL은 다음과 같이 된다.
SELECT A.EMPID,
DECODE(B.GRAD + B.ADV,NULL,1,B.GRAD + B.ADV) 순위
FROM (SELECT POINT_D,ROWNUM GRAD,ADV
FROM
(SELECT A.POINT_D POINT_D,
SUM(B.CNT) ADV
FROM (SELECT 1/POINT POINT_D CNT
FROM TEST20
GROUP BY 1/POINT
) A,
(SELECT 1/POINT POINT_D,COUNT(*)-1 CNT
FROM TEST20
GROUP BY 1/POINT
) B
WHERE B.POINT_D(+) < A.POINT_D
GROUP BY A.POINT_D
)
) B,
TEST20 A
WHERE 1/A.POINT = B.POINT_D
두번째 방법이 훨씬 복잡해 보인다.
하지만 효율적이다.
RECORD수에 따라 RESPONSE TIME이 지수함수적으로 늘어나는 SQL에서는
처리되는 RECORD수를 줄일수록 효과가 크다.
중복점수가 많을수록 두번째방법이 효과적이다.
처리할 RECORD수를 중복되는 숫자만큼 줄여주기때문이다.
뒷풀이.
PLAN상으로는 거의 차이가 없다.
PLAN만을 놓고 보면 오히려 두번째 방법이 복잡하다.
참고로 두가지 방법의 각각에 대한 PLAN을 보자.
방법1.
SELECT STATEMENTCost Estimate:
SORTORDER BY
SORTGROUP BY
NESTED LOOPSOUTER
TABLE ACCESSFULL:HABC,,,TEST20(1)
TABLE ACCESSFULL:HABC,,,TEST20(2)
방법2.
SELECT STATEMENTCost Estimate:
MERGE JOIN
SORTJOIN
TABLE ACCESSFULL:HABC,,,TEST20(7)
SORTJOIN
VIEW(1)
COUNT
VIEW(2)
SORTGROUP BY
NESTED LOOPSOUTER
VIEW(3)
SORTGROUP BY
TABLE ACCESSFULL:HABC,,,TEST20(4)
VIEW(5)
SORTGROUP BY
TABLE ACCESSFULL:HABC,,,TEST20(6)
1280건의 DATA 중 다른점수가 714건인 경우의 RESPONSE TIME이다.
방법1.
1280 행이 선택되었습니다
구문분석 0.02 (경과됨) 0.00 (CPU)
실행/인출 9.67 (경과됨) 0.00 (CPU)
합계 9.69 0.00
방법2.
1280 행이 선택되었습니다
구문분석 0.01 (경과됨) 0.00 (CPU)
실행/인출 24.53 (경과됨) 0.00 (CPU)
합계 24.54 0.00
사족.
항상 얘기하듯이 여기서 제시되는 방법이 최적의 방법은 아니다.
그건 본인도 자신할 수 가 없다.
단지 실무에서 부딪히는 각 경우대해 참고할 수 있는 자료만
되었으면 하는 바램이다.
여러가지 어려운 문제에 부딪쳤을때 혼자 고민하고 보내는 시간이
이 책으로 인해 조금이라도 줄 수 있다면 하는 바램이 있을 뿐이다.
그걸위해 내가 만났던 사례들을 모아놓는다.
조건.
TABLE : TEST20
EMPID POINT
---------- ----------
A00000 49
A00600 56
A01000 47
A01002 34
A01400 29
A02002 22
A04003 18
A09100 14
A09200 13
A10000 39
A10002 20
A10600 46
A11000 37
A11002 24
A11400 19
A12002 12
A14003 28
A19100 24
A19200 23
A90002 10
위와같이 TEST20 TABLE에 사번별 점수가 들어있다.
문제.
위의 DATA를 이용하여 석차를 구하여 순위별로
보여주고싶다.
석차를 구하는 방식은 일반적으로 우리가 알고 있는 것과 동일하다.
즉, 동일점수가 2명이상이면 동일점수는 같은 순위가 부여되고
다음 점수는 그만큼 건너뛴 순위가 부여되어야 한다.
먼저 답을 보면 다음과 같다.
EMPID 순위
---------- ----------
A00600 1
A00000 2
A01000 3
A10600 4
A10000 5
A11000 6
A01002 7
A01400 8
A14003 9
A11002 10
A19100 10
A19200 12
A02002 13
A10002 14
A11400 15
A04003 16
A09100 17
A09200 18
A12002 19
A90002 20
생각.
어렵게 생각하면 어려워지고 쉽게 생각하면 쉬운 문제다.
문제를 해결하는 방법은 모든 문제가 그렇듯이 하나 이상이
나올 수 있다.
물론 방법에 따라 결과가 나오는 시간이 다를수 는 있다.
엿보기1.가장쉽게 생각할 수 있는것은 각 사번별로 자기보다 점수가
큰 사람의 숫자를 세어서 거기에 1을 더하는 방식이다.
주의할 것은 자기점수보다 크거나 같은 사람의 숫자가
자기의 석차가 아니라는 것이다.
자기 점수와 동일인이 여러명 있을수 있기 때문이다.
방법은 간단하다.
SELF JOIN을 이용하되 한쪽을 자기보다 큰점수로 비교하고
순위 1인 사람을 위하여 (+) 기호를 붙여주면된다.
엿보기2.다음 방법도 같은 원리다.
큰점수부터 순위가 붙어야 하므로 먼저 1을 각 점수별로
나누어서 각 점수별로 GROUP을 만든다.
엿보기3.다음은 역시 같은방식으로 인원수를 구해서 1을 빼준다.
그리고 두개의 DATASET을 1/점수로 부등호 JOIN을 걸어준다.
JOIN된 결과를 1/점수로 GROUP 지으면 1/점수대별로
각각 자신의 GROUP 지어진 순위와 자신보다 상위순위중
동일 점수로 인해 중복된 인원수를 구할수 있다.
엿보기4.이제 TABLE을 한번 더 읽어서 1/점수로 다시 JOIN을 걸고
EMPID를 가져오고,순위와 중복인원을 더해주면 된다.
두번째 방법은 말로만 이해하기에 약간의 어려움이
있을 듯하다
이해가 안가면 해법을 통해 이해할 수 있는 길을 찾아보자.
해법.엿보기를 통해 두가지 방법이 제시되었는데 어떤방법이 더 빠를지
한번 생각을 해보고 해법을 접하기 바란다.
두가지 모두가 부등호 JOIN이다.
앞의 주제에서도 다뤘듯이 SELF JOIN이 부등호로써 연결될때는
DATA의 숫자가 증가함에 따라 RESPONSE TIME이 지수함수적으로
증가한다는 것을 알고있다.
단계1.첫번째 단계에서는 엿보기1에서 방식을 SQL문으로 옮겨보겠다.
SELECT A.EMPID,
COUNT(B.EMPID ) + 1
FROM TEST20 A,
TEST20 B
WHERE B.POINT(+) > A.POINT
GROUP BY A.EMPID
ORDER BY COUNT(B.EMPID)
엿보기1을 통해 충분한 설명이 있었으므로 이해하기에 어려움이
없으리라 본다.
단계2.각 점수대별 중복인원수를 구하는 방법은 다음과 같다.
SELECT 1/POINT POINT_D,COUNT(*) - 1 CNT
FROM TEST20
GROUP BY 1/POINT
단계3.위의 DATASET을 다시 점수대별로 부등호 JOIN을 거는 방법은
다음과 같다.
SELECT A.POINT_D POINT_D,
SUM(B.CNT) ADV
FROM (SELECT 1/POINT POINT_D CNT
FROM TEST20
GROUP BY 1/POINT
) A,
(SELECT 1/POINT POINT_D,COUNT(*) - 1 CNT
FROM TEST20
GROUP BY 1/POINT
) B
WHERE B.POINT_D(+) < A.POINT_D
GROUP BY A.POINT_D
점수대별 중복인원수 구하는 DATASET이 B 이다.
단계4.위의 결과를 이용해 점수대별 순위와 순위에 더해질
중복인원수를 구하려면
다음과 같이 DATASET을 FROM절로 넣고 SELECT절만 추가한다.
SELECT POINT_D,ROWNUM GRAD,ADV
단계5.위의 결과 다시 자기 TABLE과 부등호로 연결하여 사번과함께
순위 + 중복인원을 읽어오면된다.
최종 SQL은 다음과 같이 된다.
SELECT A.EMPID,
DECODE(B.GRAD + B.ADV,NULL,1,B.GRAD + B.ADV) 순위
FROM (SELECT POINT_D,ROWNUM GRAD,ADV
FROM
(SELECT A.POINT_D POINT_D,
SUM(B.CNT) ADV
FROM (SELECT 1/POINT POINT_D CNT
FROM TEST20
GROUP BY 1/POINT
) A,
(SELECT 1/POINT POINT_D,COUNT(*)-1 CNT
FROM TEST20
GROUP BY 1/POINT
) B
WHERE B.POINT_D(+) < A.POINT_D
GROUP BY A.POINT_D
)
) B,
TEST20 A
WHERE 1/A.POINT = B.POINT_D
두번째 방법이 훨씬 복잡해 보인다.
하지만 효율적이다.
RECORD수에 따라 RESPONSE TIME이 지수함수적으로 늘어나는 SQL에서는
처리되는 RECORD수를 줄일수록 효과가 크다.
중복점수가 많을수록 두번째방법이 효과적이다.
처리할 RECORD수를 중복되는 숫자만큼 줄여주기때문이다.
뒷풀이.
PLAN상으로는 거의 차이가 없다.
PLAN만을 놓고 보면 오히려 두번째 방법이 복잡하다.
참고로 두가지 방법의 각각에 대한 PLAN을 보자.
방법1.
SELECT STATEMENTCost Estimate:
SORTORDER BY
SORTGROUP BY
NESTED LOOPSOUTER
TABLE ACCESSFULL:HABC,,,TEST20(1)
TABLE ACCESSFULL:HABC,,,TEST20(2)
방법2.
SELECT STATEMENTCost Estimate:
MERGE JOIN
SORTJOIN
TABLE ACCESSFULL:HABC,,,TEST20(7)
SORTJOIN
VIEW(1)
COUNT
VIEW(2)
SORTGROUP BY
NESTED LOOPSOUTER
VIEW(3)
SORTGROUP BY
TABLE ACCESSFULL:HABC,,,TEST20(4)
VIEW(5)
SORTGROUP BY
TABLE ACCESSFULL:HABC,,,TEST20(6)
1280건의 DATA 중 다른점수가 714건인 경우의 RESPONSE TIME이다.
방법1.
1280 행이 선택되었습니다
구문분석 0.02 (경과됨) 0.00 (CPU)
실행/인출 9.67 (경과됨) 0.00 (CPU)
합계 9.69 0.00
방법2.
1280 행이 선택되었습니다
구문분석 0.01 (경과됨) 0.00 (CPU)
실행/인출 24.53 (경과됨) 0.00 (CPU)
합계 24.54 0.00
사족.
항상 얘기하듯이 여기서 제시되는 방법이 최적의 방법은 아니다.
그건 본인도 자신할 수 가 없다.
단지 실무에서 부딪히는 각 경우대해 참고할 수 있는 자료만
되었으면 하는 바램이다.
여러가지 어려운 문제에 부딪쳤을때 혼자 고민하고 보내는 시간이
이 책으로 인해 조금이라도 줄 수 있다면 하는 바램이 있을 뿐이다.
그걸위해 내가 만났던 사례들을 모아놓는다.
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
86 | 중복 data를 찾아 한번만 display하는 방법 | 운영자 | 2002.11.23 | 3428 |
85 | 중복 data를 찾아 모두 display 하는 방법 | 운영자 | 2002.11.23 | 3070 |
84 | oracle의 procedure에서의 여러 리턴값의 활용 예 | 운영자 | 2002.10.18 | 8301 |
83 | 특정문자까지의 왼쪽 문자열 반환 function | 운영자 | 2002.10.18 | 4044 |
82 | 중복자료 확인 및 삭제 | 운영자 | 2002.09.25 | 3259 |
81 | RECORD단위 DATA를 COLUMN단위로 | 운영자 | 2002.09.18 | 3681 |
80 | 누계 COLUMN이 없는 TABLE에 누계 값을 보자 (부등호 JOIN) | 운영자 | 2002.09.18 | 5104 |
79 | 바로이전 ROW의 값을 참조하고자 할때 | 운영자 | 2002.09.18 | 8619 |
78 | 누계 COLUMN이 없는 TABLE에 누계 값을 보자 (IN-LINE VIEW) | 운영자 | 2002.09.18 | 3123 |
77 | 자기보다 작은값중 최대값 하나만 읽어오기 | 운영자 | 2002.09.18 | 4588 |
76 | DATA COPY를 이용한 QUERY | 운영자 | 2002.09.18 | 3186 |
75 | PARAMETER값 변경에따른 유연한 GROUP BY | 운영자 | 2002.09.18 | 4127 |
74 | PAIRWISE 와 NONPAIRWISE | 운영자 | 2002.09.18 | 2697 |
73 | 동일한 값 안보여주기 | 운영자 | 2002.09.18 | 2969 |
72 | 소계/합계 함께 보기 | 운영자 | 2002.09.18 | 3134 |
» | 석차구하기 | 운영자 | 2002.09.18 | 2960 |
70 | COLUMN을 ROW로 | 운영자 | 2002.09.18 | 6135 |
69 | 최대값과 최소값을 뺀 평균 | 운영자 | 2002.09.18 | 4177 |
68 | 누계를 구하는 또한가지 방법 | 운영자 | 2002.09.18 | 3209 |
67 | 그룹 단위별 일련번호 붙이기 | 운영자 | 2002.09.18 | 5754 |