지난주 문제
내 답 -> CASE 로도 풀어보기 나중에!
select decode( lower(telecom), 'skt' , 'sk',
'lgu+' , 'lg' ,
'lgt' , 'lg' , lower(telecom)) as 통신사 , min(age) as 최소나이
from emp17
where lower(telecom) in ('kt' , 'lg' , 'sk')
group by lower(telecom)
order by 통신사 asc;
※위 답 오답임!! where 사용 아니고, group by 에 select 에 쓴거 그대로 써줘야함!!
select decode( lower(telecom), 'skt' , 'sk',
'lgu+' , 'lg' ,
'lgt' , 'lg' , lower(telecom)) as 통신사 , min(age) as 최소나이
from emp17
group by decode( lower(telecom), 'skt' , 'sk',
'lgu+' , 'lg' ,
'lgt' , 'lg' , lower(telecom))
order by 통신사 asc;
이게 맞는거임
예제. 사원 테이블에서 평균 월급을 출력하시오
select avg(sal) from emp;
문제 168. 위의 결과를 다시 출력하는데, 소수점 이하가 안나오게 반올림하시오
select round( avg(sal),0) from emp;
round ( avg(sal)) 으로 0 없이 써줘도 됨
문제 169.
우리반 테이블에서 평균 나이를 출력하시오select round( avg(age)) from emp17;
문제 170.
사원 테이블에서 직업, 직업별 평균 월급을 출력하시오select job, round( avg(sal)) from emp group by job;
문제 171.
위의 결과를 다시 출력하는데, 직업별 평균월급이 높은 것부터 출력하시오select job, round( avg(sal)) from emp group by job order by 2 desc;
- order by 뒤에 컬럼 순서대로 번호 매겨서 (혹은 컬럼 별칭) 쓰면 됨!
- order by 절은 코딩도 맨 마지막, 실행도 맨 마지막
문제 172.
문제 171번을 다시 수행하는데 직업이 SALEMAN 은 제외하고 출력하시오select job, round( avg(sal)) from emp where job !='SALESMAN' group by job order by 2 desc;
* where 절에 검색조건 주기
* 코딩 순서 : select -> from -> where -> group by -> order by
문제 173.
이름과 커미션을 출력하시오select ename, comm from emp;
- null 생김!
문제 174.
커미션의 평균값을 출력하시오select round( avg(comm)) from emp;
* 그룹함수는 null 값을 무시한다.
* 그래서 평균값을 구할때 null 인 값은 제외하고 나눠짐
문제 175.
위의 결과를 다시 출력하는데전체 사원수로 나눠져서평균 커미션이 계산되게 하시오
(null 값을 무시하지 않게)select avg( nvl(comm,0) ) from emp;
※ SQL 작성시, max, min 구할 때는 상관없으나 평균값 avg 쓸 때는 NULL 처리를 어떻게 할지 생각하는게 중요함
결측치 어떻게 할지 미리 상의하고 SQL 작성하기~!
문제 176.
커미션의 결측치가 몇개가 있는지 확인하시오
(커미션의 NULL값이 몇개가 있는지 조회하시오)select count(*) from emp where comm is null;
- *의 의미 :
asterisk모든 컬럼을 다 출력해라!- null 앞에는 = 말고 is 사용하기
로 쓰게 되면 그룹함수는 null값을 무시하기때문에 0이 출력된다 (아무것도 안나온다)select count( comm) from emp where comm is null;
count 사용할 때는 select 에 * 쓰는게 좋다!! 그래야 null 값을 무시하지 않고 데이터를 잘 가져올 수 있다. (OCP 시험용)
문제 177.
부서번호, 부서번호별 평균 월급을 출력하시오
- 결측치 먼저 확인하기
- 월급에 null 값이 있는지 확인부터하기
select count(*) from emp where sal is null;
- 그 다음에 위의 부서번호와 부서번호별 평균 월급 출력
select deptno, round( avg(sal),0) from emp group by deptno;
- 평균 월급 -> avg 로 평균값 / 소수점 없애기 -> round 로
▶ 합계 구하는 database 의 그룹함수
ex) 사원 테이블의 월급의 토탈값을 출력하시오
select sum(sal)
from emp;
문제 178.
직업, 직업별 토탈월급을 출력하시오select job, sum(sal) from emp group by job;
문제 179.
위의 결과를 다시 출력하는데 직업을 ABCD 순서대로 정렬하여 출력하시오select job, sum(sal) from emp group by job order by 1 ;
- order by job asc 가능
문제 180.
위의 결과를 다시 출력하는데, 직업이 'SALESMAN' 은 제외하고 출력하시오select job, sum(sal) from emp where job !='SALESMAN' group by job order by 1 ;
- where절의 위치는 from 과 group 사이이고,
SALESMAN '' 빼먹지 말기
문제 181.
180번 결과를 다시 출력하는데, 직업별 토탈 월급이 5000이상인 것만 출력하시오select job, sum(sal) from emp where job !='SALESMAN' and sum(sal) >= 5000 group by job order by 1 ;
오답 -> 에러메세지/ 3행에 오류 ORA-00934 : 그룹 함수는 허가되지 않습니다.
그룹함수는 where 절에 (검색조건) 쓸 수 없음!!! having 절에 사용해야 한다.
select job, sum(sal) from emp where job !='SALESMAN' group by job having sum(sal) >= 5000 order by 1 ;
select -> 보고싶은 컬럼명
from -> 테이블명
where -> 검색조건
group by -> 그룹핑할 컬럼
having -> 그룹함수로 검색 조건을 줄 때 사용
order by -> 정렬할 컬럼
select job, sum(sal)
from emp
group by job
having sum(sal) >= 5000 and job !='SALESMAN'
order by job asc;
실행은 되나, job !='SALESMAN' 은 성능 저하의 원인파악 할 때 사용
explain plan for
select job, sum(sal)
from emp
where job !='SALESMAN'
group by job
having sum(sal) >= 5000
order by 1 ;
select * from table(dbms_xplan.display);
위에꺼 먼저 컨트롤 엔터 한다음에 '설명되었습니다' 나오면 밑에꺼 컨트롤 엔터해야 나옴
Id 부분에서 2-1-0 순서로 실행된거임 (table access full (where절)) 부터 수행 한거
문제 182. (복습문제)
이름, 입사일, 입사한 년도(4자리) 출력하시오select ename, hiredate, to_char(hiredate, 'RRRR') from emp;
문제 183.
입사한 년도(4자리), 입사한 년도별 토탈 월급을 출력하는데
입사한 년도를 ascending 하게 출력하시오select to_char(hiredate, 'RRRR'), SUM(sal) from emp group by to_char(hiredate, 'RRRR') order by 1 asc ;
문제 184.
문제 183을 다시 수행하는데,
입사한 년도가 1981, 1982, 1983 년만 출력하시오select to_char(hiredate, 'RRRR'), SUM(sal) from emp group by to_char(hiredate, 'RRRR') where to_char(hiredate, 'RRRR') in (1981, 1982, 1983) order by 1 asc ;
라고 했는데 아님
select to_char(hiredate, 'RRRR'), SUM(sal) from emp where to_char(hiredate, 'RRRR') in ('1981', '1982', '1983') group by to_char(hiredate, 'RRRR') order by 1 asc ;
- where 앞에 꺼가 문자니까 in 뒤에도 '' 써서 문자로 작성해야함
문제 185.
문제 184번을 다시 수행하는데,
입사한 년도별 토탈월급이 4000이상인 것만 출력하시오select to_char(hiredate, 'RRRR'), SUM(sal) from emp where to_char(hiredate, 'RRRR') in ('1981', '1982', '1983') group by to_char(hiredate, 'RRRR') having sum(sal) >= 4000 order by 1 asc ;
- 그룹함수인 sum(sal) >= 를 검색조건으로 사용하기 위해서, having 절에 사용
문제 186.
성씨, 성씨별 평균 나이를 출력하시오select substr( ename, 1, 1), round( avg(age)) from emp17 group by substr( ename, 1, 1) ;
문제 187.
위의 결과를 다시 출력하는데 성씨가 김씨, 이씨, 최씨는 제외하고 출력하시오select substr( ename, 1, 1), round( avg(age)) from emp17 where substr( ename, 1, 1) not in ('김' , '이' , '최') group by substr( ename, 1, 1) ;
- 여러개를 써야하니까 where 절에 in 사용, 아니니까 not 붙이기 not in 사용
문제 188. (점심시간 문제)
문제 187번을 다시 수행하는데,
성씨별 평균나이가 29 이상만 출력되게 하고
성씨가 ㄱㄴㄷㄹ 순으로 출력되게 하시오select substr( ename, 1, 1), round( avg(age)) from emp17 where substr( ename, 1, 1) not in ('김' , '이' , '최') group by substr( ename, 1, 1) having round( avg(age)) >= 29 order by 1 asc;
COUNT : 특정행 (row)의 건수를 출력하는 그룹함수
ex) 사원 테이블의 전체 건수가 어떻게 되는가?
select count (*)
from emp;
select count(empno)
from emp;
※ (OCP 시험문제) 다음중 null값의 여부와 관계없이 결과가 잘 카운트 되는 SQL 은 무엇인가?
1. select count(comm) from emp;
2. select count(mgr) from emp;
3. select count(* ) from emp;
문제 189.
직업이 'SALESMAN'인 사원들의 인원수를 출력하시오select count(*) from emp where job='SALESMAN';
문제 190.
직업, 직업별 인원수를 출력하시오select job, count(*) from emp group by job;
문제 191.
위의 결과를 다시 출력하는데, 직업별 인원수가 높은 것부터 출력하시오select job, count(*) from emp group by job order by job desc;
라고 했는데 오답
select job, count(*) from emp group by job order by 2 desc;
~~ * 뒤에꺼 (카운트) 를 정렬해줘야함!
~~ >
문제 192.
문제 191번을 다시 출력하는데, 직업별 인원수가 2명이상인 것만 출력하시오select job, count(*) from emp group by job having count(*) >= 2 order by 2 desc;
문제 193.
문제 192번을 다시 수행하는데, 출력되는 결과에서 직업이 SALESMAN 은 제외하시오select job, count(*) from emp group by job where job not in 'SALESMAN' having count(*) >= 2 order by 2 desc;
라고 했는데 오답
select job, count(*) from emp where job != 'SALESMAN' group by job having count(*) >= 2 order by 2 desc;
* group 보다 where가 먼저 나와야 하고, not in 아니고 !=
문제 194. (OCP 시험문제)
emp 테이블에 직업의 종류가 몇개가 있는지 출력하시오select count(distinct job) from emp group by job;
라고 썼는데,, 오답
select count(distinct job) from emp;
group by 절 쓰는거 아님 ㅠ
문제 195.
어제 만들었던 서울시 소상공인 데이터인 market_2022 테이블의 전체건수를 출력하시오select count(*) from market_2022;
문제 196.
서울 강남구에 스타벅스 매장이 몇개가 있는지 출력하시오select count(*) from market_2022 where 상호명='스타벅스' and 시군구명='강남구';
라고 했음
select count(*) from market_2022 where 상호명 like '%스타벅스%' and 시군구명='강남구';
* like 쓰고 % 써야함
>
문제 197.
상호명에 스타벅스가 포함되어져 있는 데이터에서,
시군구명, 시군구명별 건수를 출력하는데
시군구명별 건수가 높은 것부터 출력하시오select 시군구명, count(*) from market_2022 where 상호명 like '%스타벅스%' group by 시군구명 order by 2 desc;
- count(* ) 에서 별 자리에 시군구명 쓰면 안됨?
문제 198. 위에서 출력되는 결과중에서 맨 첫번째 행 하나만 출력하시오
select 시군구명, count(*) from market_2022 where 상호명 like '%스타벅스%' group by 시군구명 order by 2 desc fetch first 1 row only;
- fetch first 1 row only -> 오라클에서 쓰이는 특이한 장치
※ order by 컬럼 desc/asc fetch first 숫자 row only;
정렬 된 것 기준에서 '숫자' 만큼의 줄을 가져오겠다!
문제 199.
상호명에 '스타벅스' 를 포함하고 있는 상권업종소분류명 이 무엇인지 조회하시오select * from market_2022 where 상호명 like '%스타벅스%';
문제 200.
market_2022 테이블에서 상권업종중분류명 이 '커피점/카페' 인 상호명, 상호명별 건수를 출력하는데 상호명별 건수가 높은 것부터 출력하시오select 상호명, count(*) from market_2022 where 상권업종중분류명 like '%커피점/카페%' group by 상호명 order by 2 desc;
- 이렇게 했을때 아직 스타벅스 xx점 같은거는 따로 나온다. 그리고 맨위에 '카페' 가 뜸
문제 201. 위의 결과를 다시 출력하는데, 상호명이 '카페' 는 제외하고 출력하시오
select 상호명, count(*) from market_2022 where 상권업종중분류명 ='커피점/카페' and 상호명 !='카페' group by 상호명 order by 2 desc;
- 요기서는 like 안되나염?
문제 202. 위의 SQL을 수정하는데 다음과 같이 수정하시오
※ 정확한 데이터를 보기위한 전처리 과정select case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' else 상호명 end as 상호명, count(*) from market_2022 where 상권업종중분류명 ='커피점/카페' and 상호명 !='카페' group by case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' else 상호명 end order by 2 desc;
- case when 써서 상호명에 스타벅스를 포함하고 있으면 '스타벅스' 로 출력하고 그렇지 않으면 그냥 상호명을 나타내라.
- group by 절에도 case 그대로 쓰기 (as는 빼고 end 까지만)
문제 203.
위의 SQL 에 CASE문에 '메가엠지씨커피'와 '투썸플레이스' 를 추가해서 Group by 하시오select case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' when 상호명 like '%메가엠지씨커피%' then '메가엠지씨커피' when 상호명 like '%투썸플레이스%' then '투썸플레이스' else 상호명 end as 상호명, count(*) from market_2022 where 상권업종중분류명 ='커피점/카페' and 상호명 !='카페' group by case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' when 상호명 like '%메가엠지씨커피%' then '메가엠지씨커피' when 상호명 like '%투썸플레이스%' then '투썸플레이스' else 상호명 end order by 2 desc;
문제 204.
위의 SQL을 그대로 market_2017 에서 검색하시오select case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' when 상호명 like '%메가엠지씨커피%' then '메가엠지씨커피' when 상호명 like '%투썸플레이스%' then '투썸플레이스' else 상호명 end as 상호명, count(*) from market_2017 where 상권업종중분류명 ='커피점/카페' and 상호명 !='카페' group by case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' when 상호명 like '%메가엠지씨커피%' then '메가엠지씨커피' when 상호명 like '%투썸플레이스%' then '투썸플레이스' else 상호명 end order by 2 desc;
※ 회사의 데이터 베이스 서버 종류 2가지
문제 205.
이름, 월급, 월급에 대한 순위를 출력하시오select ename, sal, rank() over (order by sal desc) as 순위 from emp;
- rank() over ()
- over 뭐뭐 이상이다~ 혹은 뒷괄호를 확장해라~
- 공동 등수 일 때 공동 다음을 다음 숫자로 하고 싶으면,
rank 앞에 dense_ 추가select ename, sal, dense_rank() over (order by sal desc) as 순위 from emp;
문제 206.
우리반 테이블에서 이름, 나이, 나이에 대한 순위를 출력하시오select ename, age, rank() over (order by age desc) as 순위 from emp17;
문제 207.
우리반 테이블에서 나이가 33은 순위가 몇위인가?select rank(33) within group (order by age desc) as 순위 from emp17;
문제 208.
사원 테이블에서 월급이 1250은 순위가 몇위인가?select rank(1250) within group (order by sal desc) as 순위 from emp;
문제 209. 직업, 이름, 월급, 순위를 출력하는데 순위가 직업별로
각각 월급이 높은 순서대로 순위를 부여하시오select job, ename, sal, rank() over (partition by job order by sal desc) as 순위 from emp;
- group by 가 아니라 partition by 사용해야함
- 직업은 중복되서 나올수 있음! 순위를 나눠서 나오는거
문제 210.
우리반 테이블에서 성별, 이름, 나이, 순위를 출력하는데
순위가 성별별로 각각 나이가 높은 순서대로 순위를 부여하시오select gender, ename, age, rank() over (partition by gender order by age desc) as 순위 from emp17;
dense_rank : 같은 순위가 여러개 있어도 그 다음 순위로 바로 출력할 수 있게 해주는 데이터 분석 함수
(데이터 warehouse 가 있는 서버에서 수행함)
스마트폰에서 주문 -> 미들웨어 (ex. 턱시도) 인서트 -> OLTP 서버 -> dw 서버 (창고서버)
문제 211.
부서번호, 이름, 입사일, 순위를 출력하는데
순위가 부서번호별로 각각 먼저 입사한 사원순으로 순위를 부여하시오
(dense_rank() 함수를 이용해서 수행하세요)select deptno, ename, hiredate, dense_rank() over (partition by deptno order by hiredate asc) from emp;
문제 212.
우리반에서 통신사, 이름, 나이, 순위를 출력하는데
순위가 통신사별로 각각 나이가 높은 순으로 순위를 부여하시오select case when lower(telecom) like '%skt%' then 'sk' when lower(telecom) like '%lgu+%' then 'lg' when lower(telecom) like '%lgt%' then 'lg' else lower(telecom) end as lower(telecom), ename, age, dense_rank() over (partition by lower(telecom) order by age desc) as 순위 from emp17 group by case when lower(telecom) like '%skt%' then 'sk' when lower(telecom) like '%lgu+%' then 'lg' when lower(telecom) like '%lgt%' then 'lg' else lower(telecom) end;
라고 썼는데 오류
그룹바이 왜 안씀?select substr(lower(telecom),1,2), ename, age, dense_rank() over (partition by substr(lower(telecom),1,2) order by age desc) as 순위 from emp17;
이거나
select case when lower(telecom) like '%skt%' then 'sk' when lower(telecom) like '%lgu+%' then 'lg' when lower(telecom) like '%lgt%' then 'lg' else lower(telecom) end as 통신사, ename, age, dense_rank() over (partition by case when lower(telecom) like '%skt%' then 'sk' when lower(telecom) like '%lgu+%' then 'lg' when lower(telecom) like '%lgt%' then 'lg' else lower(telecom) end order by age desc) as 순위 from emp17;
로 해도 나옴!
문제 213.
위의 결과에서 각 통신사별로 순위가 1등만 나오게 하시오select substr(lower(telecom),1,2), ename, age, dense_rank() over (partition by substr(lower(telecom),1,2) order by age desc) as 순위 from emp17 where 순위 = 1;
위와 같이 검색할 수 없다.
select 통신사, ename, age, 순위 from ( select substr(lower(telecom),1,2) as 통신사, ename, age, dense_rank() over (partition by substr(lower(telecom),1,2) order by age desc) as 순위 from emp17 ) where 순위 = 1;
- from 절에 괄호써서 괄호안의 sql을 먼저 실행시킴 -> 서브쿼리 사용
문제 214.
문제 203번의 SQL을 수행해서 결과가 잘 나오는지 확인하시오select case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' when 상호명 like '%메가엠지씨커피%' then '메가엠지씨커피' when 상호명 like '%투썸플레이스%' then '투썸플레이스' else 상호명 end as 상호명, count(*) from market_2022 where 상권업종중분류명 ='커피점/카페' and 상호명 !='카페' group by case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' when 상호명 like '%메가엠지씨커피%' then '메가엠지씨커피' when 상호명 like '%투썸플레이스%' then '투썸플레이스' else 상호명 end order by 2 desc;
문제 215.
위의 결과를 다시 출력하는데 상호명, 상호명별 건수, 순위를 출력하는데
순위가 상호명별 건수가 높은 순서대로 순위를 부여하시오select 상호명, 건수, rank() over (order by 건수 desc) 순위 from ( select case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' when 상호명 like '%메가엠지씨커피%' then '메가엠지씨커피' when 상호명 like '%투썸플레이스%' then '투썸플레이스' else 상호명 end as 상호명, count(*) as 건수 from market_2022 where 상권업종중분류명 ='커피점/카페' and 상호명 !='카페' group by case when 상호명 like '%스타벅스%' then '스타벅스' when 상호명 like '%이디야커피%' then '이디야' when 상호명 like '%메가엠지씨커피%' then '메가엠지씨커피' when 상호명 like '%투썸플레이스%' then '투썸플레이스' else 상호명 end order by 2 desc) ;
- 상호명, 건수 컬럼을 먼저 만들어주기 위해서 from 절에서 먼저 수행되게 함
- 순위를 뽑을 때 from 절에 서브쿼리 쓰는거 많이 쓰임!
문제 216.
market_2022 테이블에서 상호명에 떡볶이가 포함된 상호명과
그 건수를 출력하는데 그 건수가 높은 것부터 출력하시오select 상호명, count(*) from market_2022 where 상호명 like '%떡볶이%' group by 상호명 order by 2 desc;
문제 217. (오늘의 마지막 문제)
다음과 같이 제대로 결과가 출력될 수 있도록 SQL을 작성하시오 (10위까지만..?)
- 문제 203번 참고
select case when 상호명 like '%신전%' then '신전떡볶이' when 상호명 like '%죠스%' then '죠스떡볶이' when 상호명 like '%떡볶이참%' then '떡볶이참잘하는집떡참' when 상호명 like '%두끼%' then '두끼떡볶이' when 상호명 like '%신참%' then '신참떡볶이' when 상호명 like '%우리할매%' then '우리할매떡볶이' when 상호명 like '%동대문%' then '동대문엽기' when 상호명 like '%응급실%' then '응급실국물떡볶이' when 상호명 like '%걸작떡볶이%' then '걸작떡볶이' when 상호명 like '%감탄%' then '감탄떡볶이' else 상호명 end as 상호명, count(*) from market_2022 where 상호명 like '%떡볶이%' group by case when 상호명 like '%신전%' then '신전떡볶이' when 상호명 like '%죠스%' then '죠스떡볶이' when 상호명 like '%떡볶이참%' then '떡볶이참잘하는집떡참' when 상호명 like '%두끼%' then '두끼떡볶이' when 상호명 like '%신참%' then '신참떡볶이' when 상호명 like '%우리할매%' then '우리할매떡볶이' when 상호명 like '%동대문%' then '동대문엽기' when 상호명 like '%응급실%' then '응급실국물떡볶이' when 상호명 like '%걸작떡볶이%' then '걸작떡볶이' when 상호명 like '%감탄%' then '감탄떡볶이' else 상호명 end order by 2 desc;