# SQL 명령어 - 3

## 서브쿼리

> 서브쿼리는 SELECT 명령에 의한 데이터 질의로, 상부가 아닌 하부의 부수적인 질의를 의미한다.

서브쿼리에 들어가기 전 먼저 알아둬야 할 것은 스칼라 라는 개념이다. 스칼라는 주로 수학공부를 할 때 배우는 개념인데 여기서도 사용이 됨. 아주 간단하게 스칼라는 표에서의 단 하나의 `셀` 이라고 생각하면 될 것 같다. 이 셀 하나로 조건문 다채롭게 사용할 수 있게 된다. 아래와 같은 테이블이 있다고 할 때, `a` 값이 가장 작은 레코드를 삭제하려면 어떻게 해야할까?

| N | a   |
| - | --- |
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |

```
DELETE FROM table WHERE a = 100;
```

으로 명령을 입력하면 될 것이다. 만약 테이블이 굉장히 크다면 어떻게 할 것인가? 그때도 마우스 휠을 휙휙 돌리면서 a의 가장 작은 값을 직접 찾은 다음에 조건문으로 지워줄 것인가??? 정답은 `스칼라` 를 이용하는 것이다.\
위의 조건문을 다시 보자. `a` 가 가장 작다는 것은 `min` 값을 이용해서 구할 수 있을 것이다. 그리고 `min`의 결과는 단 하나의 행이다. 단 하나의 행에 단 하나의 열이 합쳐지면 단 하나의 `셀`인 스칼라가 나온다. 즉 아래와 같은 쿼리를 입력하면 스칼라가 나온다. 그리고 이 `스칼라를 조건문`에 넣음으로써 멋진 쿼리를 만들 수 있게 됨.

```
SELECT MIN(a) FROM table
```

그러면 다시 테이블에서 a 의 값이 가장 작은 레코드를 삭제하기 위해서는 어떻게 해야할까? 아래와 같다.

```
DELETE FROM tale WHERE a = (SELECT MIN(a) FROM table);
```

하나의 쿼리문안에 쿼리가 들어가서 `서브쿼리`라고 부른다.

**주의**

만약 GROUP BY를 사용하면 원하는대로 동작하지 않을 수 있다. 왜냐하면 집계함수는 보통 단 하나의 행만을 결과로 주는데 GROUP BY 를 사용하면 집계함수의 결과가 하나의 행이 아닌 다수의 행이 나오기 때문.

### **SELECT 구에서 서브쿼리 사용하기**

> 서브쿼리는 WHERE 구에서만이 아니라 다양한 구에서 사용할 수 있다.

SELECT구에서 서브쿼리를 지정할 떄는 스칼라 서브쿼리가 필요하다.

```
SELECT
  (SELECT COUNT(*) FROM table1) AS T1,
  (SELECT COUNT(*) FROM table2) AS T2;
```

### **SET 에서 서브쿼리 사용하기**

```
UPDATE table SET a = (SELECT MAX(a) FROM table);
```

### **FROM 구에서 서브쿼리 사용하기**

> 그동안은 FROM 에서 테이블만을 지정해왔다.

FROM 구에 서브쿼리를 지정하는 경우에도 서브쿼리의 기술 방법은 같다. 다만 FROM 구에는 기본적으로 테이블을 지정하는 만큼 다른 구와는 조금 상황이 다름.\
\&#xNAN;***SELECT 나 SET 구에서는 스칼라 서브쿼리를 지정해야 하지만 FROM 구에서는 스칼라 값을 반환하지 않아도 좋다!***\
물론 스칼라를 사용해도 상관은 없음.

```
SELECT * FROM (SELECT * FROM sample) sm;
```

위와 같은 형태를 중첩구조 또는 내포구조라고 부른다.

### 상관 서브쿼리

> 서브쿼리를 사용해 DELETE 명령과 SELECT 명령을 결합할 수 있었다. 그렇다면 서브쿼리의 결과가 단순 스칼라가 아니라면?

### **EXISTS**

EXISTS를 사용하면 서브쿼리가 반환하는 결괏값이 있는지를 조사할 수 있다. 특히 서브쿼리가 반드시 스칼라 값을 반환할 필요가 없다. EXISTS는 단지 반환된 행이 있는지를 확인하고 값이 있으면 참, 없으면 거짓을 반환한다.

| no | a    |
| -- | ---- |
| 1  | NULL |
| 2  | NULL |
| 3  | NULL |
| 4  | NULL |
| 5  | NULL |

> table1

| no2 |
| --- |
| 3   |
| 5   |

> table2

위와 같은 테이블이 두 개 있다고 생각해보자. table1 를 업데이트 하는데 그 조건이 table2에 존재하는 값이라고 생각해보자. 즉 결과로서 아래와 같은 테이블이 나오도록 만들어보자.

| no | a    |
| -- | ---- |
| 1  | NULL |
| 2  | NULL |
| 3  | ㅋㅋㅋ  |
| 4  | NULL |
| 5  | ㅋㅋㅋ  |

이전에 공부했던 서브쿼리를 사용하면 금방 할 수 있을거 같다. 하지만 우리는 단순 스칼라 값만을 이용해서 바꾸는 것만 했었지만 여기서는 3과 5 라는 두 개의 행에 대해서 값을 변경해줘야 한다. 일단 배운대로 써보면

```
UPDATE table1 set a = 'zzz' WHERE no = (select * from table2);
```

물론 당연히 안된다. 이 때 `EXISTS`를 사용해주면 된다.

```
UPDATE table1 SET a = `zzz` WHERE
  EXISTS (SELECT * FROM table2 WHERE no2 = no);
```

위의 명령을 해석해보자면 table2에 있는 레코드 중에 table1에도 있는 레코드를 찾아서 하나의 뷰를 만든다. 이렇게 되면 결과로서 `(3, 5)`가 결과로서 나온다. 그리고 table1을 `UPDATE`를 하는데 그 조건이 `(3, 5)` 에 존재하는 레코드.
