SQL

2022.1.5 오늘의 공부

Positive_Monster 2022. 1. 6. 00:35
더보기

▣오늘의 주요 키워드

  1. SEQUENCE
  2. SYNONYM(동의어)
  3. INDEX
  4. COMMENT
  5. TRUNCATE
  6. 분석함수

★ sequence

  • 자동일련번호를 생성하는 객체
  • Sequence 객체를 생성하려면 create sequence 시스템권한이 필요

select * from session_privs; --sequence권한확인

> SEQUENCE 객체 생성
create sequence id_seq; -- sequence객체 생성
select * from user_sequences where sequence_name = 'ID_SEQ'; --sequence객체 확인
-시퀀스 기본값

create table seq_test(id number, name varchar2(30), day timestamp); --seq_test테이블 생성
insert into seq_test(id,name,day) values(id_seq.nextval,'홍길동', localtimestamp); --nextval : 가상컬럼
select * from seq_test;
insert into seq_test(id,name,day) values(id_seq.nextval,'박찬호', localtimestamp); --nextval : 가상컬럼
select * from seq_test;

select id_seq.currval from dual; --현재 사용한 번호를 리턴

 

- sequence이름.nextval : 가상컬럼, 현재사용가능한 번호를 리턴해준다.
- sequence이름.currval : 현재사용한 번호를 리턴해준다.

 

rollback; --롤백
select * from seq_test;

insert into seq_test(id,name,day) values(id_seq.nextval,'홍길동', localtimestamp); --nextval : 가상컬럼
select * from seq_test;
insert into seq_test(id,name,day) values(id_seq.nextval,'박찬호', localtimestamp); --nextval : 가상컬럼
select * from seq_test;
select id_seq.currval from dual; -- 현재 사용한 번호를 리턴

- rollback을 하여 다시 값을 넣었는데 id값이 1,2로 들어간 것이 아니라 3,4로 들어가고 현재사용한 번호는 4가 되었다. 즉 nextval을 사용하여  sequence를 수행하고 롤백해도 번호는 롤백이 되지않고 계속 count된다는 것을 알 수 있다.

 

> SEQUENCE 삭제
drop sequence id_seq;
select * from seq_test;
select * from user_sequences where sequence_name = 'ID_SEQ';

 

- sequence는 삭제됐지만 삽입한 값들은 그대로 있다.

 

create sequence id_seq
start with 1 -- 1부터 시작
maxvalue 3 -- 최대 3까지
increment by 1 -- 1씩 증가
nocycle -- cycle 하면 계속 123123반복
nocache -- 매번 nextval할 때마다 생성하겠다, cache 20
;
select * from user_sequences where sequence_name = 'ID_SEQ'; --last_number : 다음사용번호

insert into seq_test(id,name,day) values(id_seq.nextval,'나얼', localtimestamp); --행 추가
select * from seq_test;

select * from user_sequences where sequence_name = 'ID_SEQ';
- sequence 'id_seq'확인

-  다음번호를 last_number가 2로 알 수 있다.

 

insert into seq_test(id,name,day) values(id_seq.nextval,'윤건', localtimestamp); 
select * from seq_test;
select * from user_sequences where sequence_name = 'ID_SEQ';

insert into seq_test(id,name,day) values(id_seq.nextval,'커리', localtimestamp); 
select * from seq_test; --번호가 겹치게됨(키값이 충돌)
select * from user_sequences where sequence_name = 'ID_SEQ';

insert into seq_test(id,name,day) values(id_seq.nextval,'손흥민', localtimestamp); 
select * from seq_test; 
--nextval꽉차서 오류, maxvalue를 3으로 했기 때문에

> sequence 수정
alter sequence id_seq
maxvalue 100; --id_seq의 maxvalue를 100으로 변경

select * from user_sequences where sequence_name = 'ID_SEQ';

insert into seq_test(id,name,day) values(id_seq.nextval,'손흥민', localtimestamp); 
select * from seq_test;

rollback;

> sequence 수정, start with 만 제외하고 다른 옵션들은 수정할 수 있다.
alter sequence id_seq
increment by 2
maxvalue 100
cache 20;
select * from user_sequences where sequence_name = 'ID_SEQ';


drop table seq_test;
drop sequence id_seq;


★ SYNONYM(동의어)

  • 긴 객체 이름을 짧은 이름으로 사용하는 객체
  • CREATE SYNONYM 시스템권한 필요하다.
  • 모든 유저들이 사용할 수 있는 synonym을 생성하려면 create public synonym 시스템권한이 있어야 한다. (dba(sys)에게 권한을 받아야함)
select * from session_privs; --시스템 권한 확인

create table emp_copy_2022 as select * from employees;
select * from emp_copy_2022;

> synonym 생성
create synonym ec2 for emp_copy_2022; -- 나혼자만 사용할 수 있는 synonym, 다른 유저는 사용 불가(권한 필요)
select * from user_synonyms where table_name = 'EMP_COPY_2022'; 
select * from ec2;
select * from emp_copy_2022;

user_synonyms
ec2, emp_copy_2022;

> synonym 삭제
drop synonym ec2;
select * from user_synonyms where table_name = 'EMP_COPY_2022';

select * from user_tab_privs; --테이블 시스템권한 확인
grant select on hr.employees to ora; --hr안써도 됨,ora유저에게 employees테이블 select할 수 있는 권한 주기
--select on hr.employees하는 유저들에게 내 synonym을 쓰게 하고 싶다?
grant select on hr.departments to ora; --ora유저에게 departments테이블 select할 수 있는 권한 주기
select * from user_tab_privs;

(ora유저 워크시트에서 진행)
select * from user_tab_privs;
select * from hr.employees;

select e.*, d.*
from hr.employees e, hr.departments d --소유자의 테이블을 사용할 때 너무 길지 않느냐
where e.department_id = d.department_id;

- ora유저는 departments, employees테이블을 select할 수 있는 권한을 받음, 그러나 synonym을 사용할 수는 없다.

 

(hr유저에서)
> public synonym 생성
create public synonym emp for hr.employees; --오류
create public synonym dept for hr.departments; --오류

- synonym을 다른 유저도 사용하도록 하고 싶은 때 create public synonym을 사용하면되는데 create public synonym 또한 권한이 있어야 하기때문에 dba(sys)에게 권한을 받아야한다.

(dba 워크시트에서)
grant create public synonym to hr; --hr유저에게 create public synonym 권한 부여
create public synonym emp for hr.employees; -- public synonym 생성
create public synonym dept for hr.departments; -- public synonym 생성
select * from user_synonyms; -- 내가 만든PUBLIC SYNONYM 정보 확인 불가
select * from all_synonyms where table_owner = 'HR'; -- 내가 만든PUBLIC SYNONYM 정보 확인

user_synonyms
all_synonyms

(ora 유저 워크시트에서)
select * from all_synonyms where table_owner = 'HR'; --synonym이 아직 남아있더라도 권한이 없으면 사용불가
select * from emp;
select * from dept;

select e.*, d.*
from emp e, dept d
where e.department_id = d.department_id;

(hr유저 워크시트)

> select 권한을 회수
revoke select on hr.employees from ora;
revoke select on hr.departments from ora;

(ora유저 워크시트)

select * from all_synonyms where table_owner = 'HR'; --synonym이 아직 남아있더라도 권한이 없으면 사용불가
select * from emp; --오류
select * from dept; --오류

(hr유저)
> public synonym 삭제
drop public synonym emp; -- drop을 수행하면 오류 발생(drop public synonym 시스템권한이 없기 때문에)

- drop public synonym 또한 마찬가지로 권한을 받아야 수행할 수 있다.

(dba유저)
grant drop public synonym to hr; -- hr에게 drop public synonym 권한주기
> public synonym 삭제
drop public synonym emp; -- drop을 수행하면 오류 발생(drop public synonym 시스템권한이 없기 때문에)
select * from session_privs;

drop public synonym emp; --emp synonym 삭제
drop public synonym dept; --dept synonym 삭제
select * from all_synonyms where table_owner = 'HR'; -- 내가 만든PUBLIC SYNONYM 정보 확인


※optimizer : SQL문을 수행하기 위한 실행계획을 만든다.

 

select *
from hr.employees
where employee_id = 100;

★ Data access method
책 = 테이블
페이지(page) = block(4k,(8k),16k,32k)
문장 = 행(row)
특정한 단어(오라클) 찾아야 한다.?

> full table scan (특정한 테이블에 특정한 단어를 찾을 때 첫번째 block에서부터 마지막block까지 access하는 방식)
- 테이블 첫 번째 행부터 마지막 행까지 access하는 방식

> rowid scan : 행의 물리적 주소를 가지고 찾는 방식, 데이터 access방법중에 가장 빠른 방법(예)집주소)
    1) BY USER ROWID SCAN
        select * from employees where rowid = 'AAAEAbAAEAAAADNAAA'; --f10
    2) BY INDEX ROWID SCAN
        select * from employees where employee_id = 100; --f10
select rowid, employee_id
from employees;

rowid
BY USER ROWID SCAN
BY INDEX ROWID SCAN

select * from employees where rowid = 'AAAEAbAAEAAAADNAAA';
사원번호 100번 사원의 행주소를 rowid('AAAEAbAAEAAAADNAAA')를 대신 기억해줄래?

rowid : 물리적 row 주소

1)
AAAEAb(6자리) : data object id
select * from user_objects; --DATA_OBJECT_ID가 NULL은 저장공간이 필요없는 테이블

2)
AAE(3자리) : file id
select * from dba_data_file; --오류(dba에서 수행) 

3)
AAAADN(6자리) : block id
select * from user_segments where segment_name = 'EMPLOYEES';
select * from user_extents where segment_name = 'EMPLOYEES';

4)
AAA(3자리) : row slot id(찾고싶은 row가 있는 위치)

1
2

 

3 user_extents


★ INDEX

  •  by index rowid scan 방식을 사용해서 검색속도를 높이기 위해서 사용되는 객체
  • 인덱스를 이용해서 행을 검색하면 i/o(입력/출력)를 줄일 수 있다.
  • 인덱스를 테이블과는 독립적으로 생성된다.
  • 인덱스는 오라클이 자동으로 유지관리한다.
  • primary key, unique 제약조건을 생성하면 unique index가 자동으로 생성된다.
  •  수동으로 생성한다.

 

select * from user_indexes where table_name = 'EMPLOYEES'; -- 인덱스 확인

--( 예)책의 색인페이지에 장번호가 여러개면 nonunique, 하나면 unique)
--중복되는 값이 있으면 nonunique, 유일한 값이면 unique

select * from user_ind_columns where table_name = 'EMPLOYEES'; --인덱스 컬럼 확인

drop table emp purge; --기존 emp 테이블 삭제

create table emp as select * from employees; --emp 테이블 생성, employees테이블 복제(ctas)
desc emp -- 컬럼 , 타입, 값, not null만 복제됨

select * from user_constraints where table_name = 'EMP'; --제약조건 not null만 복제되고 나머지는 복제x
select * from user_cons_columns where table_name = 'EMP'; -- 제약조건 컬럼
select * from user_indexes where table_name = 'EMP'; --index는 복제되지 않음
select * from user_ind_columns where table_name = 'EMP';--index는 복제되지 않음

user_constraints
user_cons_columns
user_indexes
user_ind_columns

select * from emp where employee_id = 100; 
--f10번키 누르고 options확인 -> full table scan발생

select rowid, employee_id from emp;
select * from emp where rowid = 'AAAFCSAAEAAAAHjAAA'; -- by user rowid scan (f10)

-full 스캔이 아닌 고유의rowid를 스캔하여 수행 속도가 아주 빠르다.

 

- primary key 제약조건을 추가 (unique)
alter table emp add constraint emp_id_pk primary key(employee_id); 
select * from user_constraints where table_name = 'EMP';
select * from user_cons_columns where table_name = 'EMP';
select * from user_indexes where table_name = 'EMP';
select * from user_ind_columns where table_name = 'EMP';

user_constraints
user_cons_columns
user_indexes
user_ind_columns

select * from emp where employee_id = 100; --(f10) by index rowid scan

- 전과는 다르게 by index rowid로 옵션이 생겼다. index조건으로는 employee_id(primary key) = 100으로 

EMP_ID_PK 값을 찾고 이 인덱스 값과 같은 ROWID만 EMP테이블에서 찾아 메모리에 저장하고 마지막에 출력하는 구조이다. 밑에서 조금 더 순서있게 설명할 것이다.

select employee_id, rowid
from emp
order by 1;
emp_id_pk 인덱스에는 아래와 같은 정보들이 입력되어 있다.
EMPLOYEE_ID     ROWID
100	AAAFCFAAEAAAAI7AAA
101	AAAFCFAAEAAAAI7AAB
102	AAAFCFAAEAAAAI7AAC
103	AAAFCFAAEAAAAI7AAD
104	AAAFCFAAEAAAAI7AAE
105	AAAFCFAAEAAAAI7AAF
.......
select * from emp where employee_id = 100; 
-- (f10)by index rowid scan (emp_id_pk가 by index rowid를 가지고 emp테이블을 스캔)
1) 100번에 해당하는 rowid를 emp_id_pk 인덱스에 가서 찾기
2) 찾은 rowid가지고 emp 테이블에 access하고 종료

select * from emp where last_name = 'King'; --full table scan

- full table scan은 테이블을 전부 탐색해서 찾는 구조이며 좋지 않은 방식이다.

 

 

> nonunique index 생성

create index emp_last_name_idx on emp(last_name); --last_name은 중복값이 있기에 nonunique조건이 된다.
select * from user_indexes where table_name = 'EMP';
select * from user_ind_columns where table_name = 'EMP';

select * from emp where last_name = 'King'; -- by index rowid scan

 

select last_name, rowid
from emp 
order by 1;

 

select * from emp where last_name = 'King'; -- by index rowid scan
1) 'King'에 해당하는 rowid를 emp_last_name_idx에 가서 찾는다
2) 찾은 rowid가지고 emp 테이블에 찾아 간다.
    select * from emp where rowid = 'AAAFCSAAEAAAAHjAAA';
3) 다시 'King'에 해당하는 rowid를 emp_last_name_idx에 가서 찾는다
4) 찾은 rowid가지고 emp 테이블에 찾아 간다.
    select * from emp where rowid = 'AAAFCSAAEAAAAHjAA4';
5) 다시 'King'에 해당하는 rowid를 emp_last_name_idx에 가서 찾는다. 없으면 종료!
6) 결과 집합을 유저한테 전달
> primary key 제약조건 삭제
select * from user_constraints where table_name = 'EMP'; --제약조건 확인
select * from user_cons_columns where table_name = 'EMP';--제약조건 컬럼확인
select * from user_indexes where table_name = 'EMP'; --인덱스 확인
select * from user_ind_columns where table_name = 'EMP'; --인덱스 컬럼확인

alter table emp drop primary key; -- primary key 제약조건 삭제
- nonunique index 생성
create index emp_id_idx on emp(employee_id); -- employee_id의 인덱스 생성
select * from user_ind_columns where table_name = 'EMP';
select * from user_indexes where table_name = 'EMP';

select * from emp where employee_id = 100; -- index range scan
1) 100번에 해당하는 rowid를 emp_id_idx 인덱스에 가서 찾기
2) 찾은 rowid가지고 emp 테이블에 access
3) 다시 100번에 해당하는 rowid를 emp_id_idx 인덱스에 가서 찾아보고 없으면 종료

- index 삭제
drop index emp_id_idx;
select * from user_indexes where table_name = 'EMP';
> unique index 생성
> unique index 생성하게 되면 employee_id 컬럼의 값은 중복되는 값은 입력될 수 없다.
    꼭 unique 제약조건을 만든 것 처럼 효과를 준다.
    
        
create unique index emp_id_idx on emp(employee_id); --중복되는 값이 있으면 안됨
select * from user_constraints where table_name = 'EMP';
select * from user_ind_columns where table_name = 'EMP';
select * from user_indexes where table_name = 'EMP';
select * from emp where employee_id = 100; -- (f10) by index rowid, unique scan

create table test(id number, name varchar2(30));
create unique index test_id_idx on test(id); --unique인덱스 생성
select * from user_constraints where table_name = 'TEST'; --제약조건을 만들지 않음
select * from user_indexes where table_name = 'TEST';

insert into test(id,name) values(1,user); --user함수는 현재 insert를 수행하는 오라클 유저
select * from test;

insert into test(id,name) values(1,user);
-- id컬럼의 unique index 생성되어 있기때문에 중복되는 값이 들어오면 오류 발생
rollback;

drop table test purge; -- test테이블 삭제
select * from user_indexes where table_name = 'TEST'; 
--테이블을 삭제하면 그 테이블과 연관된 인덱스도 자동으로 삭제됨
select * from user_ind_columns where table_name = 'EMPLOYEES'; 
-- EMP_NAME_IX는 인덱스가 2개? -> 조합인덱스

select * 
from emp 
where last_name = 'King' --인덱스 있음
and first_name = 'Steven'; -- 인덱스 없음

1) 'King'에 해당하는 rowid를 emp_last_name_idx에 가서 찾는다
2) 찾은 rowid가지고 emp 테이블에 찾아 간다.
    select * from emp where rowid = 'AAAFCSAAEAAAAHjAAA' and first_name = 'Steven';
3)  이유는 first_name = 'Steven' 체크하기 위해서 emp테이블에 찾아가서 있으면
    결과 집합에 그 데이터를 저장하고 없으면 다시 다음 단계를 진행해야 한다.
4) 다시 'King'에 해당하는 rowid를 emp_last_name_idx에 가서 찾는다
5) 찾은 rowid가지고 emp 테이블에 찾아 간다.
    select * from emp where rowid = 'AAAFCSAAEAAAAHjAA4' and first_name = 'Steven';
6) 이유는 first_name = 'Steven' 체크하기 위해서 emp테이블에 찾아가서 있으면
    결과 집합에 그 데이터를 저장하고 없으면 다시 다음 단계를 진행해야 한다.
7) 다시 'King'에 해당하는 rowid를 emp_last_name_idx에 가서 찾는다. 없으면 종료!
8) 결과 집합을 유저한테 전달
emp_last_name_idx
....
Khoo	AAAFCFAAEAAAAI7AAP
King	AAAFCFAAEAAAAI7AAA
King	AAAFCFAAEAAAAI7AA4
Kochhar	AAAFCFAAEAAAAI7AAB
Kumar	AAAFCFAAEAAAAI7ABJ
Ladwig	AAAFCFAAEAAAAI7AAl
....
select * from user_ind_columns where table_name = 'EMP';
drop index emp_last_name_idx;

> 조합인덱스
create index emp_last_first_name_idx on emp(last_name, first_name);
select * from user_ind_columns where table_name = 'EMP';
select * from user_indexes where table_name = 'EMP';

select last_name, first_name, rowid
from emp
order by 1,2;
emp_last_first_name_idx
....
Khoo	Alexander	AAAFCFAAEAAAAI7AAP
King	Janette	    AAAFCFAAEAAAAI7AA4
King	Steven	    AAAFCFAAEAAAAI7AAA
Kochhar	Neena	    AAAFCFAAEAAAAI7AAB
....
select * 
from emp 
where last_name = 'King' --인덱스 있음
and first_name = 'Steven'; -- 인덱스 있음 (last_name, first_name) 조합인덱스

1) last_name = 'King'과 first_name = 'Steven' 값이 같이 존재하는 
    rowid를 emp_last_first_name_idx에 가서 찾는다
2) 찾은 rowid가지고 emp 테이블에 찾아 간다. 
    이유는 결과집합을 만들기 위해서 실제 테이블에 찾아간다. --(메모리에 저장 후 3)에서 메모리에 저장된 결과집합을 유저한테 전달)
    select * from emp where rowid = 'AAAFCSAAEAAAAHjAAA'; 
3) 다시 last_name = 'King'과 first_name = 'Steven' 값이 같이 존재하는 
    rowid를 emp_last_first_name_idx에 가서 찾아보고 없으면 종료한 후 결과집합을 유저한테 전달


★ COMMENT(주석)

-테이블 생성하면 무조건 주석달기(업무에서 어떤테이블에 어떤건지, 주석만 봐도 이런 성격의 테이블이구나 알 정도로 자세히)

-테이블과 컬럼에 주석(설명) 만든다.

drop table emp purge;
create table emp as select * from employees;

- 테이블 주석 생성
comment on table emp is '사원정보 테이블';

- 컬럼 주석 생성
comment on column emp.employee_id is '사번';
comment on column emp.department_id is '부서코드';

- 테이블 주석 내용 확인
select * from user_tab_comments where table_name = 'EMP';

- 컬럼 주석 내용 확인
select * from user_col_comments where table_name = 'EMP';

테이블 주석
컬럼 주석

- 테이블 주석 삭제
comment on table emp is ''; -- 빈문자열로 만들기

- 컬럼 주석 삭제
comment on column emp.employee_id is ''; -- 빈문자열로 만들기

select * from user_segments where segment_name = 'EMP'; --BYTES : 이 테이블의 용량

 


만약에 특정한 테이블의 데이터를 다 삭제할 것이라면 뭐하러 undo 공간에 저장을 하겠습니까?

 

★ truncate (현장에서 사용할때 주의하고 또 주의하고 또 주의하면서 사용)

- 테이블의 행을 다 삭제하는 행위는 DELETE 문과 비슷하지만 
차이점은 TRUNCATE문은 저장공간을 초기상태로 만든다. 
truncate문은 rollback을 할 수 없다.
truncate하는 대상 행은 undo공간에 입력하지 않습니다. 왜? rollback을 할 이유가 없기때문에

 

※주의 
특정한 행을 삭제하려면 delete문을 이용해야 한다.
다시 테이블 전체 행을 삭제하려면 delete문, truncate문 둘 다 사용할 수 있다.
하지만 차이점은 undo 발생하느냐(delete), 안하느냐(truncate)
또 주의 하셔야 할 점은 truncate는 rollback이 안된다. truncate했으면 영구히 행을 삭제함

 

truncate table emp;
select * from emp;


★ 분석함수

sum(salary) over() : 총합

select sum(salary) --급여 총합 : 691416
from employees;

select employee_id, department_id, salary, 691416, salary - 691416
from employees; 

select employee_id, department_id, salary, sum(salary) over(), salary -sum(salary) over()
from employees; 
--sum(salary) over()에서 over()를 사용하지 않게되면 그룹핑을 하거나 오류가 발생하는데
over()을 사용하면 각각의 값을 계산할 수 있다.

sum(salary) over()

select employee_id, department_id, salary, round(avg(salary) over()), round(salary -avg(salary) over())
from employees; 
-평균함수도 사용가능
select employee_id, department_id, salary, max(salary) over(), salary - max(salary) over()
from employees;
-최대값도 가능
select employee_id, department_id, salary, min(salary) over(), salary - min(salary) over()
from employees;
-최소값도 가능
> 누적합
select employee_id, department_id, salary, sum(salary) over(order by employee_id) 누적합
-- employee_id순서로 누적합을 구하기
from employees;

 

select e2.employee_id, e2.department_id, e2.salary, e1.sumsal
from (select department_id, sum(salary) sumsal
        from employees
        group by department_id
        order by 1) e1, employees e2
where e1.department_id = e2.department_id
order by 2;
-부서별로 각각의 급여의 누적합을 구하기

select employee_id, department_id, salary, sum(salary) over(partition by department_id) 부서별총합
-- partition by  그룹핑을해서 총합을 구하자
from employees;

select employee_id, department_id, salary, sum(salary) over(partition by department_id order by employee_id) 부서별총합 -- partition by  그룹핑을해서 총합을 구하자
from employees;

-위의 복잡한 식을 sum(salary) over(partition by department_id)로 간단히 구할 수 있다.

select employee_id, department_id, count(*) over(partition by department_id) 부서별인원수
from employees;

select employee_id, department_id, salary,
        count(*) over(partition by department_id) 부서별인원수,
        max(salary) over(partition by department_id) 부서별최고급여,
        min(salary) over(partition by department_id) 부서별최저급여
from employees;

 

select employee_id, department_id, salary, sum(salary) over(order by employee_id) 누적합 
from employees;
--employee_id 순서로 누적합을 구하기

 

TOP-N
최고 급여자 중에 10위까지 출력

1) 급여를 기준으로 내림차순 정렬
select employee_id, salary
from employees
order by salary desc;

2) 정렬한 결과를 가지고 10위까지 제한을 해야 한다.

- rownum : fetch번호를 리턴하는 가상컬럼
select rownum, employee_id
from employees;

select rownum, employee_id, salary --order by보다 where가 우선순위가 높아서 결과값이 틀리게 나온다
from employees
where rownum <= 10 -- 랜덤하게 10개 뽑아
order by salary desc; -- 랜덤하게 10개 뽑아낸 결과를 가지고 정렬

※주의 : 우리 회사에 똑같은 급여자가 없다라고 하면 아래와 같은 query문을 수행해도 되겠지만
동일한 급여를 받는 사원이 있다고 하면 절대 아래와 같은 query를 이용해서 top-n분석하면 큰일 난다.

올바른 코드
select *
from(select employee_id, salary
        from employees
        order by salary desc) e
where rownum <= 10;

- rank() : 순위를 구하는 함수, 동일한 순위가 있을 경우 다음 순위는 갭이 생길 수 있다.
- dense_rank() : 순위를 구하는 함수, 동일한 순위가 있더라도 연이은 순위를 구하는 함수
select rank() over(order by salary desc) "rank",
    dense_rank() over(order by salary desc) "dense_rank",
    employee_id, salary
from employees;

rank, dense_rank

select rank() over(partition by department_id order by salary desc) "부서별 rank",
    dense_rank() over(partition by department_id order by salary desc) "부서별 dense_rank",
    department_id, employee_id, salary
from employees;

'SQL' 카테고리의 다른 글

2022.1.6 sql 끝 그리고 다시 시작  (0) 2022.01.06
2022.1.4 오늘의 공부  (0) 2022.01.05
12.30 오늘의 공부  (0) 2021.12.30
12.29 오늘의 공부  (0) 2021.12.29
12.28 오늘의 공부  (0) 2021.12.28