데이터베이스

DATABASE STEP 19 - SubQuery

2023. 3. 21. 22:06
728x90

★ MainQuery

  • 여태까지의 SQL
  • 일반적인 SQL
  • 하나의 문장안에 하나의 select(insert, update, delete)로 구성된 쿼리

★ Sub Query, 서브 쿼리, 부속 질의

  • 하나의 문장(select, insert, update, delete)안에 또 다른 문장(select)이 들어있는 쿼리
  • 하나의 select문 안에 들어있는 또 다른 select 문
  • 삽입 위치 > 거의 대다수의 절(select 절, from 절, where 절  < 자주 사용 :: 자주사용 안함 > group by 절, having 절, order by 절)

■ 사용 ex)

  • ex1)
-- tblCountry.  인구수가 가장 많은 나라의 이름?
select *
from tblCountry;

update tblCountry set population = 120060 where name = '중국';

select max(population) -- 인구수가 가장 많은 > 120660 
from tblCountry;
select name from tblCountry where population = 120660; --중국

-- 합치면
-- 장점
-- 1. 2개의 SQL > 1개의 SQL
-- 2. 변화에 강하다. (인구수 변동) > 개발자 편의성 향상
select name from tblCountry 
    where population = (select max(population) from tblCountry);
  • ex2)
-- tblComedian. 체중이 가장 많이 나가는 사람의 이름?
select max(weight) from tblComedian;

select * from tblComedian
    where weight = (select max(weight) from tblComedian);
  • ex3)
-- tblInsa. 급여 1등?
select max(basicpay) from tblInsa; -- 2650000

select * from tblInsa
    where basicpay = (select max(basicpay) from tblInsa);
  • ex4)
-- tblInsa. 막내 직원? 이정석 05/09/26
select * from tblInsa where ibsadate = (select max(ibsadate) from tblInsa);

-- tblIsa. 왕고참? 김인수 95/02/23
select * from tblInsa where ibsadate = (select min(ibsadate) from tblInsa);

-- tblInsa. 평균 급여보다 더 많이 받는 직원?
select avg(basicpay) from tblInsa;

select * from tblInsa where basicpay >= (select avg(basicpay) from tblInsa);

-- tblInsa. '홍길동'보다 급여가 많은 직원?
select basicpay from tblInsa where name = '홍길동';

select * from tblInsa 
    where basicpay >= (select basicpay from tblInsa where name = '홍길동') and name <> '홍길동';

 

★ 서브 쿼리 삽입 위치

  • 1. 조건절
  • 2. 컬럼리스트
  • 3. from 절

 

■ 1. 조건절

  • 비교 대상(비교값) 역할 > 값
  • where 절, having 절, case문
  • a. 반환값이 1행 1열 > 단일 값 반환 > 값 1개로 취급
select * from tblInsa
    where basicpay >= (select avg(basicpay) from tblInsa);
  • b. 반환값이 N행 1열 > 다중값(같은 성질의 여러개의 데이터) 반환 > 값 N개로 취급
-- 급여가 260만원 이상 받는 직원이 근무하는 부서 직원 명단을 가져오시오. > 기획부 + 총무부
-- 01427. 00000 -  "single-row subquery returns more than one row"

select * from tblInsa
    -- where buseo(비교대상 1개) = 기획부, 총무부(비교대상 2개)
    -- where buseo = '기획부' or buseo = '총무부';
    -- where buseo in ('기획부', '총무부');  같은 성질의 N개의 데이터 > 열거형
    where buseo in (select buseo from tblInsa where basicpay >= 2600000);
    
    
-- b. 반환값이 N행 1열 > 다중 값 (같은 성질의 여러개의 데이터) 반환 > 값 N개로 취급  
-- '홍길동'과 같은 지역 + 같은 직위 > 소속 부서 직원 명단
select *from tblInsa where name = '홍길동';
select * from tblInsa where city='서울' and jikwi = '부장' ;

select city from tblInsa where name = '홍길동'; -- 서울
select jikwi from tblInsa where name = '홍길동'; --부장

select buseo from tblInsa
    where city = (select city from tblInsa where name = '홍길동')
        and jikwi = (select jikwi from tblInsa where name = '홍길동')
            and name <> '홍길동';

select * from tblInsa
    where buseo in (select buseo from tblInsa
    where city = (select city from tblInsa where name = '홍길동')
        and jikwi = (select jikwi from tblInsa where name = '홍길동')
            and name <> '홍길동');
  • c. 반환값이 1행 N열 > 다중 값(서로 다른 성질의 여러개의 데이터) 반환 
select city from tblInsa where name ='홍길동';
select jikwi from tblInsa where name = '홍길동';

select * from tblInsa where city = '서울' and jikwi = '부장';

select * from tblInsa
    where city = (select city from tblInsa where name ='홍길동')
        and jikwi = (select jikwi from tblInsa where name = '홍길동');
        
select * from tblInsa
    where (city, jikwi) = (select city, jikwi from tblInsa where name = '홍길동');
    
    
select * from tblAddressBook; 

select * from tblAddressBook
    where (gender, age, job) = (select gender, age, job
                                                                    from tblAddressBook where name = '기예주');
  • d. 반환값이 N행 N열 > 다중값 반환
-- 급여가 260만원 이상 받는 직원과 같은 부서 + 같은 지역에 있는 모든 직원?
select * from tblInsa where basicpay >= 2600000;

-- 서울 + 기획부 && 경남 + 총무부
select city, buseo from tblInsa where basicpay >= 2600000;

select * from tblInsa
    where (city, buseo) in (select city, buseo from tblInsa where basicpay >= 2600000);
    
select
    buseo,
    avg(basicpay)
from tblInsa
    group by buseo
        having avg(basicpay) >= (select avg(basicpay) from tblInsa where buseo = '개발부');

 

■ 2. 컬럼 리스트

  • 단일 데이터(값) > 원자 값 > 관계형 데이터베이스 > 표 > 속성(컬럼)의 값은 원자값이어야한다.
  • a. 컬럼명
  • b. 상수
  • c. 연산
  • d. 함수
select 
    name as "컬럼",
    100 as "상수",
    basicpay + 100 as "연산",
    length(name) as "함수"
from tblInsa;
select
    name, buseo, basicpay,
    (select round(avg(basicpay)) from tblInsa) as "평균 급여"
from tblInsa;
select
    name, buseo, basicpay,
    (select round(avg(basicpay)) from tblInsa where buseo = i.buseo) as "소속 부서 평균 급여"
from tblInsa i;

 

■ 3. from 절

  • 서브쿼리의 결과셋을 하나의 테이블이라고 생각하고, 또 다른 select를 실행
  • 구문을 단순화하기 위해서 사용
-- employees. 'Munich'에 위치한 부서에 소속된 직원 명단?
select * from employees; --department_id 소속 부서
select * from departments; -- location_id 위치 정보
select * from locations;

select location_id from locations
    where city = 'Munich';
select department_id from departments
    where location_id = (select location_id from locations
    where city = 'Munich');

select * from employees
    where department_id in (select department_id from departments
        where location_id = (select location_id from locations
            where city = 'Seattle'));

 

■ 종합 요구사항 예제 모음

  • 1. tblMen. tblWomen. 서로 짝이 있는 사람 중 남자와 여자의 정보를 모두 가져오시오. > select절
select * from tblMen;
select * from tblWomen;

select
    name, height, weight,
    (select height from tblWomen where name = m.couple) as "여자친구 키",
    (select name from tblWomen where name = m.couple) as "여자친구 이름",
    (select weight from tblWomen where name = m.couple) as "여자 몸무게"
from tblMen m;
  • 2. tblAddressBook. 가장 많은 사람들이 가지고 있는 직업은 주로 어느 지역 태생(hometown)인가? > where절
select * from tblAddressBook;

select max(count(*)) from tblAddressBook group by job;

select job from tblAddressBook
    group by job
        having count(*) = (select max(count(*)) from tblAddressBook group by job);
        
select distinct hometown from tblAddressBook
    where job = (select job from tblAddressBook
    group by job
        having count(*) = (select max(count(*)) from tblAddressBook group by job));
  • 3. tblAddressBook. 이메일 도메인들 중 평균 아이디 길이가 가장 긴 이메일 사이트의 도메인은 무엇인가? > group by + having
select 
    substr(email, instr(email, '@') +1) as "도메인",
    avg(length(substr(email, 1, instr(email, '@') -1))) as "평균 아이디 길이"
from tblAddressBook
    group by substr(email, instr(email, '@') +1)
        having avg(length(substr(email, 1, instr(email, '@') -1))) = 
        (select 
            max(avg(length(substr(email, 1, instr(email, '@') -1))))
        from tblAddressBook
            group by substr(email, instr(email, '@') +1));
    
select 
    max(avg(length(substr(email, 1, instr(email, '@') -1))))
from tblAddressBook
    group by substr(email, instr(email, '@') +1);
  • 4. tblAddressBook. 평균 나이가 가장 많은 출신(hometown)들이 가지고 있는 직업 중 가장 많은 직업은? > where + group by + having
select * from tblAddressBook;

select 
    max(avg(age))
from tblAddressBook
    group by hometown;
    
select
    hometown
from tblAddressBook
    group by hometown
        having avg(age) = 
        (select 
            max(avg(age))
        from tblAddressBook
        group by hometown);
    

select 
    hometown,
    round(avg(age))
from tblAddressBook
    group by hometown
        having max(avg(age));

select 
        max(count(*))
from tblAddressBook
    where hometown = '광주'
        group by job;

select
    max(avg(age))
from tblAddressBook
    group by hometown; -- 38.6875

select
    hometown
from tblAddressBook
    group by hometown
        having avg(age) = (select
                                max(avg(age))
                            from tblAddressBook
                                group by hometown);

select
    max(count(*))
from tblAddressBook
    where hometown = '광주'
        group by job;

select
    job
from tblAddressBook
    where hometown = (select
                            hometown
                        from tblAddressBook
                            group by hometown
                                having avg(age) = (select
                                                        max(avg(age))
                                                    from tblAddressBook
                                                        group by hometown))
        group by job
            having count(*) = (select
                                    max(count(*))
                                from tblAddressBook
                                    where hometown = (select
                                                            hometown
                                                        from tblAddressBook
                                                            group by hometown
                                                                having avg(age) = (select
                                                                                        max(avg(age))
                                                                                    from tblAddressBook
                                                                                        group by hometown))
                                        group by job);
  • 5. tblAddressBook. 남자 평균 나이보다 나이가 많은 서울 태생 + 직업을 가지고 있는 사람들을 가져오시오. > where절
select * from tblAddressBook;
select 
    avg(age)
from tblAddressBook
    where gender = 'm';
    
select *
from tblAddressBook
    where job is not null;
    
select 
    name, job, hometown
from tblAddressBook
    where age > (select 
                            avg(age)
                        from tblAddressBook
                            where gender = 'm') and hometown = '서울' and job <> '백수';
  • 6. tblAddressBook. gmail.com을 사용하는 사람들의 성별 > 세대별(10,20,30,40대) 인원수를 가져오시오. > where절
select * from tblAddressBook;

select 
    gender, age
from tblAddressBook
    where substr(email, instr(email, '@') +1) = 'gmail.com';
    
select 
    count(case
        when gender = 'm' and age between 10 and 19 then 1 
    end) as "남자 10대",
    count(case
        when gender = 'f' and age between 10 and 19 then 1 
    end) as "여자 10대",
    count(case
        when gender = 'm' and age between 20 and 29 then 1 
    end) as "남자 20대",
    count(case
        when gender = 'f' and age between 20 and 29 then 1 
    end) as "여자 20대",
    count(case
        when gender = 'm' and age between 30 and 39 then 1 
    end) as "남자 30대",
    count(case
        when gender = 'f' and age between 30 and 39 then 1 
    end) as "여자 30대",
    count(case
        when gender = 'm' and age between 40 and 49 then 1 
    end) as "남자 40대",
    count(case
        when gender = 'f' and age between 40 and 49 then 1 
    end) as "여자 40대"
from (select 
            gender, age
        from tblAddressBook
            where substr(email, instr(email, '@') +1) = 'gmail.com');
  • 7. -- tblAddressBook. 가장 나이가 많으면서 가장 몸무게가 많이 나가는 사람과 같은 직업을 가지는 사람들을 가져오시오. > where절
select * from tblAddressBook;

select 
    max(age)
from tblAddressBook;

select
    max(weight)
from tblAddressBook;

select
    job
from tblAddressBook
    where age = (select 
                            max(age)
                        from tblAddressBook) 
        and weight = (select
                            max(weight)
                        from tblAddressBook);



select *
from tblAddressBook
    where job = (select
                            job
                        from tblAddressBook
                            where age = (select 
                                                    max(age)
                                                from tblAddressBook) 
                                and weight = (select
                                                    max(weight)
                                                from tblAddressBook));
  • 8. tblAddressBook.  동명이인이 여러명 있습니다. 이 중 가장 인원수가 많은 동명이인(모든 이도윤)의 명단을 가져오시오. > where절
select * from tblAddressBook;

select 
    max(count(*))
from tblAddressBook
    group by name;


    
select 
    name
from tblAddressBook
    group by name
        having count(*) = (select 
                                    max(count(*))
                                from tblAddressBook
                                    group by name);
    
select *
from tblAddressBook
    where name = (select 
                            name
                        from tblAddressBook
                            group by name
                                having count(*) = (select 
                                                            max(count(*))
                                                        from tblAddressBook
                                                            group by name));
  • 9. tblAddressBook. 가장 사람이 많은 직업의(332명) 세대별 비율을 구하시오.> where + group by + having
SELECT 
    job,
    round(count(CASE
        when age between 10 and 19 then 1
    end)/count(*)*100,2)||'%' as "[10대]",
    round(count(CASE
        when age between 20 and 29 then 1
    end)/count(*)*100,2)||'%' as "[20대]",
    round(count(CASE
        when age between 30 and 39 then 1
    end)/count(*)*100,2)||'%' as "[30대]",
    round(count(CASE
        when age between 40 and 49 then 1
    end)/count(*)*100,2)||'%' as "[40대]"
FROM tbladdressbook group by job having count(job) = (SELECT max(count(job)) FROM tbladdressbook group by job);
728x90
저작자표시 비영리 변경금지 (새창열림)

'데이터베이스' 카테고리의 다른 글

DATABASE STEP 21 - JOIN  (2) 2023.03.21
DATABASE STEP 20 - RDBMS&Foreign key  (0) 2023.03.21
DATABASE STEP 18 - Having 절  (2) 2023.03.20
DATABASE STEP 17 - Group By  (0) 2023.03.18
DATABASE STEP 16 - Update&Delete  (0) 2023.03.18
'데이터베이스' 카테고리의 다른 글
  • DATABASE STEP 21 - JOIN
  • DATABASE STEP 20 - RDBMS&Foreign key
  • DATABASE STEP 18 - Having 절
  • DATABASE STEP 17 - Group By
IT의 큰손
IT의 큰손
IT계의 큰손이 되고 싶은 개린이의 Log 일지
Developer Story HouseIT계의 큰손이 되고 싶은 개린이의 Log 일지
IT의 큰손
Developer Story House
IT의 큰손
전체
오늘
어제
  • 분류 전체보기 (457)
    • 정보처리기사 필기 (18)
    • 정보처리기사 실기 (12)
    • 정보처리기사 통합 QUIZ (12)
    • 빅데이터 (11)
    • 안드로이드 (11)
    • 웹페이지 (108)
    • 자바 (49)
    • SQLD (3)
    • 백준 알고리즘 (76)
    • 데이터베이스 (41)
    • 깃허브 (2)
    • Library (14)
    • Server (31)
    • 크롤링&스크래핑 (3)
    • Spring (23)
    • Vue.js (13)
    • React (27)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • Developer Stroy House

인기 글

태그

  • 개발자
  • DBA
  • 웹개발
  • 정보처리기사
  • React
  • 코딩테스트
  • 개발블로그
  • css
  • 백준
  • IT자격증공부
  • 알고리즘
  • 정보처리기사필기
  • html
  • JavaScript
  • 백엔드
  • jquery
  • 자바
  • jsp
  • IT개발자
  • DB
  • ajax
  • it
  • 데이터베이스
  • 웹페이지
  • 프론트엔드
  • 정보보안전문가
  • java
  • IT자격증
  • 앱개발자
  • 웹개발자

최근 댓글

최근 글

Designed By hELLO
IT의 큰손
DATABASE STEP 19 - SubQuery
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.