# 20강. 행 개수 구하기 - COUNT
대표적인 집계함수는 다음과 같은 5개를 꼽을 수 있다.
**`집계함수`**
```
COUNT(집합)
SUM(집합)
AVG(집합)
MIN(집합)
MAX(집합)
```

- SQL은 데이터베이스라 불리는 '데이터 집합'을 다루는 언어이다.
- 집합의 개수나 합계가 궁금하다면 SQL이 제공하는 집계함수를 사용하여 간단하게 구할 수 있다.

---

## 1. COUNT로 행 개수 구하기
- SQL은 집합을 다루는 `집계함수`를 제공한다.
- 일반적인 함수는 인수로 하나의 값을 지정하는 데 비해 집계함수는 인수로 집합을 지정한다.
- 이 때문에 집합함수라고 부르기도 한다.
- 즉, 집합을 특정 방법으로 계산하여 그 결과를 반환한다.
- `COUNT` 함수는 인수로 주어진 집합의 개수를 구해 반환한다.

**`COUNT`**
```
COUNT(집합)
```

**`COUNT로 행 개수 계산`**
```
SELECT COUNT(*) FROM sample51;
```

- 인수로 `*`가 지정되어 있는데 이는 `SELECT` 구에서 '모든 열`을 나타낼 때 사용하는 메타문자와 같다.
- 다만 이때 `COUNT` 집계함수에서는 '모든 열 = 테이블 전체'라는 의미로 사용한다.
- 즉, `COUNT`는 인수로 지정된 집합(이 경우는 테이블 전체)의 개수를 계산하는 것이다.

##### COUNT 집계함수로 행 개수를 구할 수 있다!

- 집계함수의 특징은 복수의 값(집합)에서 하나의 값을 계산해내는 것이다.
- 일반적인 함수는 하나의 행에 대하여 하나의 값을 반환한다.
- 한편 집계함수는 집합으로부터 하나의 값을 반환한다.
- 이렇게 집합으로부터 하나의 값을 계산하는 것을 '집계'라 부른다.
- 이러한 이유로 집계함수를 `SELECT` 구에 쓰면 `WHERE` 구의 유무와 관계없이 결괏값으로 하나의 행을 반환한다.

### WHERE 구 지정하기
- `SELECT` 구는 `WHERE` 구보다 나중에 내부적으로 처리된다.
- 따라서 `WHERE` 구로 조건을 지정하면 테이블 전체가 아닌, 검색된 행이 `COUNT`로 넘겨진다.
- 즉, `WHERE` 구의 조건에 맞는 행의 개수를 구할 수 있다.
- 검색된 행은 `WHERE` 구의 조건에 맞는 개수가 나오지만, 최종적으로 결과는 하나의 행이 된다.

---

## 2. 집계함수와 NULL값
- `COUNT`의 인수로 열명을 지정할 수 있다.
- 열명을 지정하면 그 열에 한해서 행의 개수를 구할 수 있다.
- `*`을 인수로 사용할 수 있는 것은 `COUNT` 함수뿐이다.
- 다른 집계함수에서는 열명이나 식을 인수로 지정한다.
- 집계함수는 집합 안에 `NULL` 값이 있을 경우 이를 제외하고 처리한다.

```
SELECT COUNT(no), COUNT(name) FROM sample51;
```
- no 열에는 `NULL` 값을 가지는 행이 존재하지 않으므로 no 열의 행 개수는 5로 나타난다.
- name 열에는 `NULL` 값을 가지는 행이 하나 존재하므로, 이를 제외한 name 열의 행 개수는 4로 나타난다.
- 다만 `COUNT(*)`의 경우 모든 열의 행수를 카운트하기 때문에 `NULL` 값이 있어도 해당 정보가 무시되지 않는다.

##### 집계함수는 집합 안에 NULL 값이 있을 경우 무시한다!

---

## 3. DISTINCT로 중복 제거
- 집합을 다룰 때, 경우에 따라서는 집합 안에 중복된 값이 있는지 여부가 문제될 때도 있다.
- 데이터가 서로 중복되지 않는 경우에는 `'유일한 값을 가진다'`라는가 `'값이 중복되지 않는다'`라는 표현을 자주 한다.
- SQL의 `SELECT` 명령은 이러한 중복된 값을 제거하는 함수를 제공한다. 이때 사용하는 키워드가 바로 `DISTINCT`이다.

```
SELECT ALL name FROM sample51;
```

**`DISTINCT를 지정. 콤마는 붙이지 않는다.`**
```
SELECT DISTINCT name FROM sample51;
```

- `DISTINCT`는 예약어로 열명이 아니다.
- `SELECT` 구에서 `DISTINCT`를 지정하면 중복된 데이터를 제외한 결과를 클라이언트로 반환한다.
- 중복 여부는 `SELECT` 구에 지정된 모든 열을 비교해 판단한다.
- 앞의 예제에서 첫 번째 `SELECT` 명령에서는 `DISTINCT`가 아닌 `ALL`을 지정했는데, 이렇게하면 중복 유무와 관계없이 문자 그대로 모든 행을 반환한다.
- 즉, `SELECT` 구에 지정하는 `ALL` 또는 `DISTINCT`는 중복된 값을 제거할 것인지 설정하는 스위치와 같은 역할을 한다.
- 이때 `ALL`과 `DISTINCT` 중 어느 것도 지정하지 않은 경우에는 중복된 값은 제거되지 않는다.
- 즉, 생략할 경우에는 `ALL`로 간주된다.

##### DISTINCT로 중복값을 제거할 수 있다!

---

## 4. 집계함수에서 DISTINCT
- `NULL` 값을 제외하고, 중복하지 않는 데이터의 개수를 구하는 경우를 생각해봅니다.
- `COUNT` 함수, `DISTINCT`, `WHERE` 구의 조건을 지정해 구할 수 있는가? 구할 수 없다.
- `WHERE` 구에서는 검색할 조건을 지정하는 것밖에 할 수 없다. 중복된 값인지 아닌지를 알아보는 함수도 없다.
- `SELECT DISTINCT COUNT(name)`라는 `SELECT` 명령으로도 안 된다. `COUNT` 쪽이 먼저 계산되어버리기 때문이다.
- 이럴때는 집계함수의 인수로 `DISTINCT`를 사용한 수식을 지정하는 방법을 사용한다.
- `DISTINCT`는 집계함수의 인수에 수식자로 지정할 수 있다.
- `DISTINCT`를 이용해 집합에서 중복을 제거한 뒤 `COUNT`로 개수를 구할 수 있는 것이다.

```
SELECT COUNT(ALL name), COUNT(DISTINCT name) FROM sample51;
```

- `SELECT` 구에서의 중복삭제와 마찬가지로, `DISTINCT`가 아닌 `ALL`을 지정하면 집합 전부가 집계함수에 주어진다.
- 이때 `DISTINCT`와 `ALL`은 인수가 아니므로 콤마는 붙이지 않는다.

---