SELECT문 정복하기
SELECT
SELECT
DB에서 데이터를 검색하기 위해 사용합니다.
SELECT 할때 사용되는 연산자
- 산술 연산자
- +, -, *, /
- 비교 연산자
- =, <>, !=, <, > 등
- 논리 연산자
- NOT, AND, OR 등
- 결합 연산자
-
- 집합 연산자
- UNION ALL, UNION, INTERSECT, MINUS
- 기타 연산자
- IN, BEWTEEN, IS NULL, LIKE, EXISTS 등
가상의 테이블을 생성
SELECT 예제를 알아보기 위해 임의의 테이블을 만들겠습니다.
employee_id는 직원 ID, first_name은 이름, last_name은 성, email은 이메일 주소, phone_number는 전화번호, hire_date는 입사일, job_id는 직급, salary는 연봉, department_id는 부서 ID를 의미합니다.
CREATE TABLE korean_company (
employee_id NUMBER(4) PRIMARY KEY,
first_name VARCHAR2(20),
last_name VARCHAR2(25),
email VARCHAR2(25),
phone_number VARCHAR2(20),
hire_date DATE,
job_id VARCHAR2(10),
salary NUMBER(8,2),
department_id NUMBER(2)
);
INSERT INTO korean_company VALUES (100, '준호', '김', 'junho.kim@example.com', '010-1234-5678', TO_DATE('2021-01-01', 'YYYY-MM-DD'), 'CEO', 80000, 10);
INSERT INTO korean_company VALUES (101, '성민', '이', 'sungmin.lee@example.com', '010-2345-6789', TO_DATE('2021-01-02', 'YYYY-MM-DD'), 'CTO', 70000, 20);
INSERT INTO korean_company VALUES (102, '영희', '박', 'yeonghee.park@example.com', '010-3456-7890', TO_DATE('2021-01-03', 'YYYY-MM-DD'), 'CFO', 60000, 30);
INSERT INTO korean_company VALUES (103, '철수', '최', 'cheolsu.choi@example.com', '010-4567-8901', TO_DATE('2021-01-04', 'YYYY-MM-DD'), 'Manager', 50000, 40);
INSERT INTO korean_company VALUES (104, '수지', '한', 'suji.han@example.com', '010-5678-9012', TO_DATE('2021-01-05', 'YYYY-MM-DD'), 'Manager', 50000, 40);
INSERT INTO korean_company VALUES (105, '민지', '강', 'minji.kang@example.com', '010-6789-0123', TO_DATE('2021-01-06', 'YYYY-MM-DD'), 'Analyst', 40000, 50);
employee_id | first_name | last_name | phone_number | hire_date | job_id | salary | department_id | |
---|---|---|---|---|---|---|---|---|
100 | 준호 | 김 | junho.kim@example.com | 010-1234-5678 | 2021-01-01 | CEO | 80000.00 | 10 |
101 | 성민 | 이 | sungmin.lee@example.com | 010-2345-6789 | 2021-01-02 | CTO | 70000.00 | 20 |
102 | 영희 | 박 | yeonghee.park@example.com | 010-3456-7890 | 2021-01-03 | CFO | 60000.00 | 30 |
103 | 철수 | 최 | cheolsu.choi@example.com | 010-4567-8901 | 2021-01-04 | Manager | 50000.00 | 40 |
104 | 수지 | 한 | suji.han@example.com | 010-5678-9012 | 2021-01-05 | Manager | 50000.00 | 40 |
105 | 민지 | 강 | minji.kang@example.com | 010-6789-0123 | 2021-01-06 | Analyst | 40000.00 | 50 |
산술/비교/논리 연산자 예제
salary가 50000보다 큰 직원만 출력
SELECT employee_id, first_name, last_name, salary
FROM korean_company
WHERE salary > 50000;
employee_id | first_name | last_name | salary |
---|---|---|---|
100 | 준호 | 김 | 80000.00 |
101 | 성민 | 이 | 70000.00 |
102 | 영희 | 박 | 60000.00 |
103 | 철수 | 최 | 50000.00 |
104 | 수지 | 한 | 50000.00 |
hire_date가 2021년 1월 4일보다 이전인 직원의 이름과 입사일을 출력
SELECT first_name, hire_date
FROM korean_company
WHERE hire_date < TO_DATE('2021-01-04', 'YYYY-MM-DD');
first_name | hire_date |
---|---|
준호 | 2021-01-01 |
성민 | 2021-01-02 |
영희 | 2021-01-03 |
salary가 50000보다 크고, job_id가 Manager인 직원의 employee_id, first_name, last_name, salary, job_id 필드를 출력
SELECT employee_id, first_name, last_name, salary, job_id
FROM korean_company
WHERE salary > 50000 AND job_id = 'Manager';
employee_id | first_name | last_name | salary | job_id |
---|---|---|---|---|
103 | 철수 | 최 | 50000.00 | Manager |
104 | 수지 | 한 | 50000.00 | Manager |
salary가 50000보다 큰 직원들 중 hire_date가 2021년 1월 1일 이후인 사람들을 조회
SELECT employee_id, first_name, last_name, hire_date, salary
FROM korean_company
WHERE salary > 50000 AND hire_date >= TO_DATE('2021-01-01', 'YYYY-MM-DD');
employee_id | first_name | last_name | hire_date | salary |
---|---|---|---|---|
100 | 준호 | 김 | 2021-01-01 | 80000.00 |
101 | 성민 | 이 | 2021-01-02 | 70000.00 |
102 | 영희 | 박 | 2021-01-03 | 60000.00 |
job_id가 ‘Manager’이거나 ‘CEO’인 직원들 중 hire_date가 2021년 1월 3일 이전인 사람들을 조회
SELECT employee_id, first_name, last_name, hire_date, job_id
FROM korean_company
WHERE job_id IN ('Manager', 'CEO') AND hire_date < TO_DATE('2021-01-03', 'YYYY-MM-DD');
employee_id | first_name | last_name | hire_date | job_id |
---|---|---|---|---|
100 | 준호 | 김 | 2021-01-01 | CEO |
103 | 철수 | 최 | 2021-01-04 | Manager |
104 | 수지 | 한 | 2021-01-05 | Manager |
salary가 40000보다 큰 직원들 중 ‘이’씨 성을 가진 직원들을 조회
SELECT employee_id, first_name, last_name, salary
FROM korean_company
WHERE last_name LIKE '이%' AND salary > 40000;
employee_id | first_name | last_name | salary |
---|---|---|---|
101 | 성민 | 이 | 70000.00 |
직책이 ‘C’로 시작하는 모든 직원의 이름과 직책을 가져옵니다. 그리고 LENGTH 함수를 사용하여 이름이 긴 순서로 결과를 정렬
first_name | job_id |
---|---|
영희 | CFO |
성민 | CTO |
LIKE 연산자는 특정 패턴에 일치하는 행을 찾는 데 사용되며, ‘C%’는 ‘C’로 시작하는 문자열을 의미합니다.
ORDER BY 절은 결과를 정렬하는 데 사용되며, LENGTH 함수는 문자열의 길이를 반환합니다.
UNION(합집합) 연산자
2개의 SELECT 문의 결과 집합을 결합하여 중복된 행을 제거하고 하나의 결과 집합으로 표시하는 데 사용됩니다.
korean_company 테이블에서 job_id가 ‘CEO’인 직원과 job_id가 ‘Analyst’인 직원의 이름과 직급을 선택하면 다음과 같은 SQL 문을 작성할 수 있습니다.
SELECT first_name, last_name, job_id
FROM korean_company
WHERE job_id = 'CEO'
UNION
SELECT first_name, last_name, job_id
FROM korean_company
WHERE job_id = 'Analyst';
2개의 SELECT 문을 UNION으로 결합하고, 중복된 행을 제거하여 합집합으로 결과를 출력합니다.
FIRST_NAME | LAST_NAME | JOB_ID |
---|---|---|
준호 | 김 | CEO |
민지 | 강 | Analyst |
INTERSECT(교집합) 연산자
2개의 SELECT 문의 결과 집합에서 공통된 행만을 선택하여 하나의 결과 집합으로 표시하는 데 사용됩니다.
korean_company 테이블에서 department_id가 10인 직원과 department_id가 20인 직원이 모두 있는 부서의 ID를 선택하는 예제입니다.
SELECT department_id
FROM korean_company
WHERE department_id = 10
INTERSECT
SELECT department_id
FROM korean_company
WHERE department_id = 20;
2개의 SELECT 문을 INTERSECT로 결합하고, 공통된 행을 선택하여 교집합으로 결과를 출력합니다.
DEPARTMENT_ID |
---|
No rows selected (공통된 행이 없으므로 결과가 없습니다.) |
MINUS(차집합) 연산자
첫 번째 SELECT 문의 결과에서 두 번째 SELECT 문의 결과를 제외한 행을 선택하여 하나의 결과 집합으로 표시하는 데 사용됩니다.
korean_company 테이블에서 department_id가 40인 직원 중 job_id가 ‘Manager’인 직원의 이름과 직급을 선택하는 예제입니다.
SELECT first_name, last_name, job_id
FROM korean_company
WHERE department_id = 40 AND job_id = 'Manager'
MINUS
SELECT first_name, last_name, job_id
FROM korean_company
WHERE department_id = 40 AND job_id <> 'Manager';
두 개의 SELECT 문을 MINUS로 결합하고, 첫 번째 SELECT 문의 결과에서 두 번째 SELECT 문의 결과를 제외하여 차집합 결과를 출력합니다.
FIRST_NAME | LAST_NAME | JOB_ID |
---|---|---|
수지 | 한 | Manager |
기타 연산자
IN, ANY, ALL, SOME
ANY, SOME은 사실상 같은 것이다.
IN, ALL, SOME, ANY 연산자의 차이점을 나타낸 표입니다.
연산자 | 설명 | 예제 |
---|---|---|
IN | 비교할 값 목록 중 하나와 일치하는지 확인합니다. | SELECT * FROM employees WHERE department_id IN (10, 20, 30); |
ALL | 모든 비교 조건이 참일 때 TRUE를 반환합니다. | SELECT * FROM employees WHERE salary > ALL (SELECT salary FROM employees WHERE department_id = 30); |
SOME | 비교 조건 중 하나가 참일 때 TRUE를 반환합니다. | SELECT * FROM employees WHERE salary > SOME (SELECT salary FROM employees WHERE department_id = 30); |
ANY | SOME과 같이 작동하며, 비교 조건 중 하나가 참일 때 TRUE를 반환합니다. | SELECT * FROM employees WHERE salary > ANY (SELECT salary FROM employees WHERE department_id = 30); |
employees 테이블에서 department_id가 10, 20, 또는 30인 모든 직원의 정보를 가져오는 쿼리는 다음과 같이 작성할 수 있습니다.
SELECT * FROM employees WHERE department_id IN (10, 20, 30);
employees 테이블에서 department_id가 30인 직원보다 더 높은 급여를 받는 직원의 정보를 가져오는 쿼리는 ALL, SOME, ANY 연산자를 사용하여 다음과 같이 작성할 수 있습니다.
-- 부서 id가 30인 직원 중 최고 급여자 보다 높은 급여를 받는 직원 조회
SELECT * FROM employees WHERE salary > ALL (SELECT salary FROM employees WHERE department_id = 30);
-- 부서 id가 30인 직원 중 최소 한 명 보다 높은 급여를 받는 직원 조회
SELECT * FROM employees WHERE salary > SOME (SELECT salary FROM employees WHERE department_id = 30);
-- 부서 id가 30인 직원 중 최소 한 명 보다 높은 급여를 받는 직원 조회
SELECT * FROM employees WHERE salary > ANY (SELECT salary FROM employees WHERE department_id = 30);
``
## 사용되는 키워드
### DISTINCT
>중복된 투플을 한 번만 표시한다.
### All
>중복된 투플을 다 보여준다.
>기본 값은 ALL이다.
korean_company 테이블에서 DISTINCT를 사용하여 job_id 컬럼의 중복을 제거한 결과를 출력합니다.
SELECT DISTINCT job_id FROM korean_company;
| job_id |
| ------ |
| CEO |
| CTO |
| CFO |
| Manager|
| Analyst|
korean_company 테이블에서 ALL을 사용하여 salary가 50000 이상인 모든 직원의 employee_id와 job_id, salary를 출력합니다.
SELECT ALL employee_id, job_id, salary FROM korean_company WHERE salary >= 50000;
| employee_id | job_id | salary |
| ----------- | -------- | -------- |
| 100 | CEO | 80000.00 |
| 101 | CTO | 70000.00 |
| 102 | CFO | 60000.00 |
| 103 | Manager | 50000.00 |
| 104 | Manager | 50000.00 |
### ORDER BY
>SELECT 문에서 결과를 정렬할 때 사용됩니다. 기본적으로 오름차순(ASC)으로 정렬되며, 내림차순(DESC)으로 정렬하려면 DESC 키워드를 사용합니다.
korean_company 테이블에서 salary 필드를 기준으로 정렬하는 SELECT문을 작성하면 다음과 같습니다.
SELECT employee_id, first_name, last_name, salary FROM korean_company ORDER BY salary DESC;
위의 SELECT문은 salary 필드를 내림차순으로 정렬한 결과를 보여줍니다. 결과는 다음과 같습니다.
| employee_id | first_name | last_name | salary |
| ----------- | ---------- | --------- | --------- |
| 100 | 준호 | 김 | 80000.00 |
| 101 | 성민 | 이 | 70000.00 |
| 102 | 영희 | 박 | 60000.00 |
| 103 | 철수 | 최 | 50000.00 |
| 104 | 수지 | 한 | 50000.00 |
| 105 | 민지 | 강 | 40000.00 |
또한, 여러 개의 필드를 기준으로 정렬하려면 ORDER BY 절에 여러 개의 필드를 콤마로 구분하여 작성할 수 있습니다.
SELECT employee_id, first_name, last_name, salary, hire_date FROM korean_company ORDER BY department_id ASC, salary DESC;
위의 SELECT문은 먼저 department_id 필드를 오름차순으로 정렬하고, 그 다음으로 salary 필드를 내림차순으로 정렬한 결과를 보여줍니다. 결과는 다음과 같습니다.
| employee_id | first_name | last_name | salary | hire_date |
| ----------- | ---------- | --------- | --------- | ---------- |
| 100 | 준호 | 김 | 80000.00 | 2021-01-01 |
| 101 | 성민 | 이 | 70000.00 | 2021-01-02 |
| 102 | 영희 | 박 | 60000.00 | 2021-01-03 |
| 104 | 수지 | 한 | 50000.00 | 2021-01-05 |
| 103 | 철수 | 최 | 50000.00 | 2021-01-04 |
| 105 | 민지 | 강 | 40000.00 | 2021-01-06 |
## 다양한 함수
### 통계 함수
* SUM
* 속성의 합계
* COUNT
* 레코드의 수
* AVG
* 속성의 평균값
* MIN
* 속성의 최솟값
* MAX
* 속성의 최댓값
* **GROUP BY(중요)**
* 레코드(데이터)를 그룹화하고, 각 그룹에 대한 집계 값을 반환
### SUM, COUNT, AVG
– 학과번호가 ‘010’인 학생들의 이수학점 합계를 구하기 SELECT SUM(이수학점) AS 이수학점합계 FROM 학생 WHERE 학과번호 = ‘010’;
– 학생들이 수강 신청한 내역의 개수를 구하기 SELECT COUNT(*) AS 수강신청건수 FROM 수강;
– 학과번호가 ‘010’인 학생들의 이수학점 평균을 구하기 SELECT AVG(이수학점) AS 이수학점합계 FROM 학생 WHERE 학과번호 = ‘010’;
### GROUP BY
>레코드를 그룹화하여, 각 그룹별로 레코드 조회가 가능하다.
>GROUP BY 뒤에 있는 속성으로 레코드를 나눈다.
>그룹 기준이 되는 속성만 표시가 가능하다.
– 학과번호 별로 이수학점의 합계를 구하기 SELECT 학과번호, SUM(이수학점) AS 이수학점합계 FROM 학생 GROUP BY 학과번호;
– 학과번호가 ‘010’이 아닌 학생들의 학번과 이수학점 합계를 구하기 – 이 코드는 작동하지 않고 오류가 발생한다! SELECT 학과번호, SUM(이수학점) AS 이수학점합계 FROM 학생 WHERE 학과번호 != ‘010’ GROUP BY 학과번호;
### HAVING
>그룹 별 통계 조건을 설정하기 위해 사용한다.
위 예제의 해결책은 다음과 같다.
– 학과번호가 ‘010’이 아닌 학생들의 학번과 이수학점 합계를 구하기 – HAVING을 사용하면 된다. SELECT 학과번호, SUM(이수학점) AS 이수학점합계 FROM 학생 GROUP BY 학과번호 HAVING 학과번호 != ‘010;
### 튜플 변수를 이용한 SELECT
>튜플 변수를 사용해서, 하나의 TABLE을 두 개의 TABLE이 있는 것처럼 사용이 가능하다.
>TABLE 이름 뒤에 튜플 변수 이름을 붙이면 된다.
>**TABLE 이름에 별명을 붙여준다고 생각하면 된다!**
* 튜플 변수
* 한 레코드(행, 튜플)을 나타낸다.
SELECT t1.학번, t1.이름, t2.과목번호 FROM 학생 t1, 수강 t2 WHERE t1.학번 = t2.학번;
– 학번이 ‘9912345’인 학생보다 이수학점이 많은 학생들의 학번과 이름을 구하기 SELECT s1.학번, s1.이름 FROM 학생 s1, 학생 s2 WHERE s2.학번 = ‘9912345’ AND s1.이수학점 > s2.이수학점;
### 중첩 SELECT문
>하나의 쿼리문에 SELECT문을 여러 개 사용하는 것을 의미한다.
SELECT 학번 FROM 수강 WHERE 과목번호 = ‘cs100’ AND 학번 IN ( SELECT 학번 FROM 수강 WHERE 과목번호 = ‘cs300’ ); ```