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 email 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’ ); ```