본문 바로가기

sql

7. DATA 분석함수(rank, dens_rank, listagg, ntile, lead, lag)

728x90
반응형

데이터 분석 함수

[우리 교재엔 없는 내용]

 1. rank : 순위를 출력하는 함수

 

rank 함수

예제: 이름, 월급, 순위를 출력하는데

순위는 월급에 대한 순위이고

월급이 높은 사원부터 순위를 부여하시오

 

select ename, sal,

          rank( ) over (order by sal desc) 순위

from emp;

 

rank 순위를 출력하라

over ~이상

(order~desc) 괄호내용대로

출력해라

 

 

문제153. 이름, 나이, 순위를 출력하는데

순위가

나이가 높은 순서대로

순위를 부여하시오

 

select ename, age,

rank()over(order by age desc)순위

from emp2;

 

 

문제154. 위의 결과를 다시 출력하는데

전공이 심리학과 학생들로 제한해서

출력하시오

 

select ename, age,

rank()over(order by age desc)순위

from emp2

where major like '%심리%';

 

 

문제155.

1981년도에 입사한 사원들의

이름과 입사일과 순위를 출력하는데

먼저 입사한 사원 순으로

순위를 부여하시오.

*to_char,

 to_date & between 이용해서

 

select ename, to_char(hiredate, 'rrrr'),

rank()over(order by to_char(hiredate, 'rrrr') asc)순위

from emp

where to_char(hiredate,'rrrr') ='1981'

 

좌변 건들면 안좋으니

튜닝

select ename, hiredate,

rank()over(order by hiredate asc)순위

   from emp

   where hiredate between

     to_date('1981/01/01', 'rrrr/mm/dd')

   and

     to_date('1981/12/31', 'rrrr/mm/dd');

 

 

문제156.

이름, 월급, 순위를 출력하는데

순위가 월급이 높은 사원부터

출력하시오

(같은순위가 있어도

다음 순위로 바로 이어지게 하시오)

 

select ename, sal,

dense_rank()over(order by sal desc)순위

from emp

 

RANK(지정값)WITHIN GROUP

 

분석함수에서 지정값을 정해서

순위를 구해주는 함수다.

 

문제157.

월급이 2975 사원은

전체 사원들 중에

월급의 순위

어떻게 되는가?

 

select 

rank(2975) within group (order by sal desc)순위

from emp;

 

*********

이름도 같이 출력하고 싶었으나

rank 그룹함수라서

group by ename 묶어줘야 연산한다.

그룹:그룹 (대칭성)

 

select * from

(

select ename, sal,

rank()over(order by sal)

from emp)

where sal='2975';

 

그래서 tabel 값을 지정해줘서

그룹대칭성 조건 해제 하고

내가 where 조건을 만든다.

 

rank() over (order by~)

rank(숫자) within group (order by~)

 

 

DENSE_RANK

동순위를 하나로 간주하고

다음 순위에 영향없이 차례대로

순위를 매기는 함수다.

 

문제158.

81 11 17일에 입사한 사원은

사원 테이블에서

번째로 입사한 사원인가

(먼저 입사를 보통은 물어봄)

 

select *

from( select hiredate,

rank()over(order by hiredate asc) from emp

)

where hiredate = to_date('81/11/17', 'rr/mm/dd');

 

히히히히히히히히

select e.ename, 순위

from (select empno, dense_rank()over(order by hiredate asc)순위

      from emp) ee, emp e                        

 where ee.empno = e.empno

 and hiredate = to_date('81/11/17', 'rr/mm/dd');

 

 

 

문제159.

부서번호, 이름, 월급, 순위를 출력하는데

순위를 출력할

부서번호별로 각각 월급이 높은순서대로

순위를 출력하시오

**각각 이니까 그룹화랑은 다르지.

 

select deptno, ename, sal,

dense_rank()over(partition by deptno

                                 order by sal desc)순위

from emp;

 

partition by deptno  ->>부서별로 모아라

부서를 합친게 아니라

같은 부서를 쪼르르 나열한거다

 

그래서

select deptno, ename, sal,

dense_rank()over(partition by deptno

                                 order by sal desc)순위

from emp;

셀렉트의 각각의 부서번호, 이름, 연봉과

대칭이 되고 값이 출력되는 거다.

 

partition by group by 랑은 다르다

데이터 분석함수를 사용할

옵션으로 사용하는 키워드다

 

 

문제 160.

 통신사, 이름, 나이, 순위를 출력하는데

순위가 통신사별로 각각

나이가 높은 순서대로

순위를 부여하라

select lower(telecom),

        ename,

       age,

        dense_rank()over(partition by lower(telecom)

                                         order by age desc)순위

    from emp2;

 

*****점심시간 문제와 개념비교

lower(telecom)TC 지정했던 이유는

 서브쿼리에서 lower(telecom) 해서

그것만 개별로 돌리면 대문자로 나온다.

그래서

최상단의 select lower(telecom) 이랑

호환안됨.

 

이미 쿼리에서

변수함수로 썼기때문에

별칭 지정해서

함수역할 못하게 .

 

 

■데이터 분석 함수

1.rank

2. dense_rank

3. listagg

 

listagg 함수

 " 데이터를 가로로 출력하는 함수"

:

  부서번호, 해당 부서번호인

  사원들의 이름을 가로로 출력하시오

select deptno,

listagg(ename, ',') within group(order by ename)

from emp

group by deptno;

 

이름과 이름을 콤마로 구분해라

그룹 별로

이름 순서로

+반드시

order by,

group by 함께 와야 한다.

 

 

문제161.

입사한 년도, 입사한 년도 별로

입사한 사원들의 이름을

가로로 출력하시오

***아직도 년도,날짜의 개념이 빈약하고

hiredate 그룹화는

//일로 나눈다는 깨달아야함.

 

select to_char(hiredate,'rrrr')입사년도,

listagg(ename,',') within group(order by to_char(hiredate, 'rrrr') )이름

from emp

group by to_char(hiredate,'rrrr');

 

 

문제162.

통신사, 학생이름을 출력하는데

아래와 같이

나이도 같이 출력되게 하고

나이가 높은순서대로 출력되게하시오

SELECT LOWER(telecom),

listagg(ename||'('||age||')', ',') within GROUP ( ORDER BY age DESC )

FROM emp2

GROUP BY LOWER(telecom);

 

select lower(telecom),

Listagg(ename||'('||'age'||')', ',') within group

(order by age desc)

from emp2

group by lower(telecom);

 

싱글 쿼테이션 붙이면 이런 나옴

주의 해야함.

 

 

데이터 분석함수

1. rank

2. dense_rank

3. listagg

4. ntile

 

 

ntile 데이터 분석 함수

 "등급을 출력하는 함수"

:

  select ename, sal,

ntile(4) over (order by sal desc) 등급

from emp;

 

***14개의 sal 등급을 나눈게 아니라

0~5000 4등급으로 나눴음. (ntile(4) )

 

select ename, sal,

ntile(4) over (order by sal desc) 등급

from emp;

4개로 등급화 하라

 

 

 

문제163.

위의 결과를 다시 출력하는데

등급이 1등급인 사원들만

출력하시오

select ename, sal,

ntile(4) over (order by sal desc) 등급

from emp

where 등급='1'

 

이건 안됨. 왜냐면 실행 순서가

from->where->select

 

 

select *

from (

        select ename, sal,

            ntile(4) over (order by sal desc) 등급

                  from emp )

where 등급 ='1';

 

실행순서: 바깥 from->

            sub 쿼리의 from ->

            sub 쿼리의 select -> where

 

문제 164.

통신사, 이름, 나이, 순위를 출력하는데

통신사 별로 나이 순위가 1등인 학생들만 출력하시오.

 

 select * from

    (select telecom, ename, age,

 dense_rank()over(partition by telecom

                  order by age desc)as "순위"

      from emp2)

 where 순위 = 1;

 

 

select *

from(

select lower(telecom), ename, age,

dense_rank()over (partition by lower(telecom) order by age desc)순위

from emp2

)

where 순위 = '1';

 

 

문제165.

통신사, 이름, 나이, 순위를 출력하는데

순위가 통신사별로 각각 나이가 높은 순서대로

출력하시오

 

select *

from(

select lower(telecom), ename, age,

dense_rank()over (partition by lower(telecom) order by age desc)순위

from emp2);

 

dense_ 안쓰면

111,4,5,6, 이런식으로 순위 매겨짐.

 

 

문제 166.점심시간 문제

아래와 같이

결과를 출력하시오

*등수는 나이순대로 매겨짐.

**등수가 나이순대로 매겨지니

이름도 나이순서대로 나열되야 겠지요???

 

SELECT

TC,

 LISTAGG(ENAME || '(' || RANK_AGE_TELECOM || ')', ', ' ) WITHIN GROUP (ORDER BY AGE DESC)

 AS LISTAGG_STR_ENAME_RANK

FROM (

SELECT

UPPER(TELECOM) AS TC,

 ENAME,

 AGE,

 DENSE_RANK() OVER ( PARTITION BY UPPER(TELECOM) ORDER BY AGE DESC)

 AS RANK_AGE_TELECOM

FROM EMP2

)

GROUP BY TC;

 

************rank 에서 partition by 이유

>>등급을 telecom 전체에서 매기는게 아니라

텔레콤 마다 등급을 매기기 때문에

텔레콤으로 partition by 해줘야 한다.

 

-------------

다른답

 

select telecom as tl,

listagg(e.ename||'('||ee.rank_age||')', ',') within group(order by e.age desc)등수

from(select ename, dense_rank()over(partition by telecom

                             order by age desc) as rank_age

     from emp2) ee, emp2 e

where ee.ename = e.ename                     

group by telecom;

 

-------------------

 

*****************

용원처럼 TC 별칭지정 안하고

출력하면 에러뜬다.

왜냐하면

첫번째 문장의 select lower(telecom)

telecom 이라는 테이블에 함수 lower 씌워서 갖고 오라는 건지

서브쿼리의 lower(telecom) 갖고 오라는 건지

컴퓨터가 판단 못한다.

그래서

, 함수붙이는 중복함수 수행 안되게

별칭 지정 해주는게 좋다.

 

 

 

데이터 분석 함수

1. rank

2. dens_rank

3. listagg

4. ntile

5. 그룹함수와 관련한 데이터 분석함수

 

문제167.

토탈월급을 출력하시오

 

select sum(sal)

from emp;

 

 

문제 168.

이름, 월급, 사원 테이블 전체의 토탈월급

출력하시오

select ename, sal, sum(sal)

from  emp

group by ename, sal;

 

값이 나오긴 한데, 원하는 값이 아니다

 

그룹함수OVER( )

select ename, sal,

       sum(sal) over () as 전체토탈

  from emp;

 

토탈값은 사원테이블 전체로 묶어서 나온 .

앞의 컬럼과 함께 안묶이고

단독적으로 그룹토탈값 빼주는 기능

모든사원의 sum(sal).

이녀석이 좋은게

그룹바이 안해도 먹힌다는거.

 

select ename, sal, sum(sal) over () 전체토탈

from emp;

 

over 안에 아무것도 썼기 때문에 '전체토탈'

나온거고

()안에 넣으면 값의 토탈이 나옴.

 

over() <<< 녀석이 그룹함수를 개개항목이랑

함께 있게 해줌.

 

 

문제169.

이름, 월급, 사원 테이블의 월급의 평균값을 출력하시오

select ename, sal, round(avg(sal) over())평균

from emp;

이렇게 뽑아주면

나중에 현업에서 작업할

개인의 연봉과 평균연봉을 비교할 있다.

 

 

 

문제170.

이름, 월급, 사원 테이블의 월급의 평균값을

출력하는데

자기 월급이 사원 테이블의 월급의

평균값보다 사원들만 출력하시오

 

select ename, sal, round(avg(sal) over () )

from emp

where sal > round( avg(sal)over() );

**이거 안됨.

??????

별칭지정을 하는 이유를 모르는거임

 

*함수를 썼으면 변수다*

 

where   sal     =      ( avg(sal)over( ) )

      개개항목        개개항목+함수 적용된 변수

 

( avg(sal)over( ) ) <<< 값이

             select 절에 ( avg(sal)over( ) ) 인지

           새로이 함수적용해서 뽑으라는건지

           컴퓨터는 없다.

그래서 별칭지정이 필요하다

 

 

 

용원답

SELECT * FROM

(

 SELECT   ENAME,   SAL,

  ROUND( (AVG(SAL)  OVER()) , 2 ) AS 평균값

 FROM EMP

)

WHERE SAL>평균값

 

 

select ename, sal, round(avg(sal) over ())

from emp;

 

select * from

 (

   select ename, sal, round(avg(Sal)over()) as 평균값

   from emp)

   where sal > 평균값;

 

 

 

문제171.

부서번호, 부서번호별 평균월급을 출력하시오

(partition by 써서)

 

select

   deptno,

   round(avg(sal)over(partition by deptno))

                                     평균월급

from emp;

 

***partition by 되네 !!

 

 

 

문제172. 부서번호, 이름, 월급, 자기가 속한

부서번호의 평균월급을 출력하시오

 

select  deptno, ename, sal,

 avg(sal) over (partition by deptno) 부서평균

from emp;

***round 둘러주려면

over 항목까지 .

select  deptno, ename, sal,

 round(avg(sal) over (partition by deptno)) 부서평균

from emp;

 

 

문제173.

위의 결과를 다시 출력하는데

자기의 월급이 자기 부서의 평균월급보다

높은 사원들만

출력하는데

그들의 직업 무엇인지 확인하시오

 

**여기서부터 서브쿼리 필요함***

메인 where 지정하는 avg 값인지

               새로운 함수 avg 값인지

알수 없으니까.

 

select *

from

(

select  deptno, sal, job,

 round(avg(sal) over (partition by deptno)) 부서평균

from emp

)

where sal> 부서평균;

 

 

 

문제174.

이름, 직업, 직업별 인원수를

출력하시오

select ename, job,

count(*)  over (partition by job)인원수

from emp;

 

■누적치 출력 함수

문제175.

사원번호, 이름, 월급, 월급의 누적치 출력하시오

select empno, ename, sal,

 sum(sal) over (order by empno rows

                  between unbounded preceding

                     and

                             current row) 누적치

from emp;

 

***** empno order by 뒤에 썼냐면

그냥 사원번호 순으로 누적치가 보고 싶어서

그런거다

ename deptno 상관없다.

 

설명:

 1. unbounded preceding :       제일 번째

2. current rot             :    현재

3. unbounded following:   마지막

 

order by empno 사원번호 순으로 정렬하라

between

unbounded preceding 제일 번째

 and

 current row 현재

 

만약

current row 대신

unbounded followin 쓰면

사실상 전체 토탈 값이 나옴.

 

 

문제176.

위의 결과를 다시 출력하는데

부서번호, 사원번호, 이름, 월급, 월급의 누적치를

출력하는데

월급의 누적치가

부서번호별 각각 월급의 누적치를

출력하시오

 

select deptno, empno, ename, sal,

 sum(sal) over (partition by deptno

                   order by empno rows

                  between unbounded preceding

                     and

                             current row) 누적치

from emp;

 

 

데이터 분석 함수

1. rank

2. dens_rank

3. listagg

4. ntile

5. 그룹함수와 관련한 데이터 분석함수

6. lead, lag

 

LEAD & LAG

앞행의 값을 다음행으로 가져와서 출력하여

비교가능 하게 해주는 함수

 

:

부서번호, 이름, 월급, 월급의 전행,

                           월급의 다음행

출력

select empno, ename, sal,

         lead(sal,1) over (order by empno)as lead,

        lag(sal,1) over (order by empno) as

lag

from emp;

 

 

 

화면 캡처: 2018-10-19 오후 2:30

전행과의 차이를 구할 이용하는 함수

lead 값이

 다음행 sal 나타난다.

 

lag 값이

 전행 sal 나타난다.

 

 

문제177.

위의 결과를 다시 출력하는데

부서번호, 이름, 월급, 월급의 전행,

                           월급의 다음행

출력하는데

부서번호로 각각 나오게 하시오.

 

select deptno, empno, ename, sal,

         lead(sal,1) over (partition by deptno

                      order by empno)as lead,

        lag(sal,1) over (partition by deptno

                      order by empno) as lag

from emp;

 

 

문제178.

최대월급을 받는 사원의 이름과 월급을

출력하시오

 

select *

from

(select ename, sal, max(sal)over() as "최대월급"

from emp)

where sal = 최대월급;

 

 

소진답

SELECT *FROM

(

SELECT

ename,

sal,

DENSE_RANK() OVER(ORDER BY SAL DESC) 순위

FROM EMP)

WHERE 순위=1;

 

select *

from

(select ename, sal,

dense_rank()over(order by sal desc) 순위

from emp)

order by 순위 asc;

 

728x90
반응형

'sql' 카테고리의 다른 글

9. SUBQUERY  (0) 2019.03.30
8. JOIN  (0) 2019.03.30
6. 그룹함수  (0) 2019.03.30
5. NVL, DECODE, CASE  (0) 2019.03.30
4. 날짜함수  (0) 2019.03.30