> For the complete documentation index, see [llms.txt](https://koseungbin.gitbook.io/wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://koseungbin.gitbook.io/wiki/books/undefined-1/sql/select-1.md).

# SELECT 문을 응용해보자

## 검색결과 정렬

{% code title="정렬" %}

```sql
SELECT ~ ORDER BY 열1 [ , 열2, ... ]
```

{% endcode %}

ORDER BY 에 사용한 열명을 '정렬키' 라고 한다.&#x20;

* 오름차순 ASC (디폴)
* 내림차순 DESC

## 테이블을 요약하는 함수

SQL 에서 데이터에 대해 어떠한 조작이나 계산을 수행하려면 '함수' 라는 도구를 사용한다.

함수는 크게 2 종류로 나뉜다.

* 복수 행에 대해 집계를 수행하는 함수
* 단일 행의 값에 대해 조작이나 계산을 수행하는 함수

전자의 경우 **'집약함수(집계함수)'** 라 부른다.&#x20;

* **COUNT** 테이블의 행수를 알려주는 함수
* **SUM** 테이블의 수치 데이터를 합계하는 함수
* **AVG** 테이블의 수치 데이터 평균을 구하는 함수
* **MAX** 테이블의 임의열 데이터 중 최대값을 구하는 함수
* **MIN** 테이블의 임의열 데이터 중 최소값을 구하는 함수&#x20;

이러한 **집약함수는 기본적으로 NULL을 제외**하고 집계하는데, COUNT 함수만은 'COUNT(\*)' 로 표기하여 NULL을 포함한 전체 행을 집계한다. 또한, SUM, AVG 이외의 집약함수는 수치 데이터 외에도 이용 가능하다. 예를 들어, 도시명 최대값은 'Y' 로 시작하는 'Yosu', 최소값은 'A' 로 시작하는 'Andong' 이 된다.

```sql
mysql> select name from city where countrycode = 'KOR';
+------------+
| name       |
+------------+
| Seoul      |
| Pusan      |
| Inchon     |

~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~

| Yongchon   |
| Sachon     |
| Uiwang     |
| Naju       |
| Namwon     |
| Tonghae    |
| Mun-gyong  |
+------------+
70 rows in set (0.00 sec)

mysql> select max(name) from city where countrycode = 'KOR';
+-----------+
| max(name) |
+-----------+
| Yosu      |
+-----------+
1 row in set (0.00 sec)

mysql> select min(name) from city where countrycode = 'KOR';
+-----------+
| min(name) |
+-----------+
| Andong    |
+-----------+
1 row in set (0.00 sec)
```

## 문자열을 집약하는 GROUP\_CONCAT

문자열에 대한 집약함수는 SQL 표준에는 없으나 MySQL에는 'GROUP\_CONCAT' 함수가 있다. 'GROUP\_CONCAT' 함수는 콤마로 구분되는 문자열의 결합을 돌려준다. 만약 애플리케이션 측에서 사용시에는 함수 결과가 매우 길 수 있어 주의해야 한다.

```sql
mysql> select group_concat(name) from city where countrycode = 'KOR' and district = 'Chollabuk';
+-------------------------------------------+
| group_concat(name)                        |
+-------------------------------------------+
| Chonju,Iksan,Kunsan,Chong-up,Kimje,Namwon |
+-------------------------------------------+
1 row in set (0.00 sec)
```

## DISTINCT로 중복 회피

DISTINCT 는 선택한 행의 중복을 배제하고 싶은 경우에 이용하는데,  집약함수에도 이용할 수 있다.

{% code title="district(행정구역) 이 중복 결합" %}

```sql
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| group_concat(district)                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Seoul,Pusan,Inchon,Taegu,Taejon,Kwangju,Kyongsangnam,Kyonggi,Kyonggi,Kyonggi,Kyonggi,Chollabuk,Chungchongbuk,Kyonggi,Kyonggi,Kyongsangbuk,Kyongsangnam,Kyongsangnam,Kyonggi,Chungchongnam,Kyongsangnam,Chollabuk,Kyonggi,Kyongsangbuk,Kyonggi,Kyongsangbuk,Chollabuk,Cheju,Kyongsangnam,Chollanam,Chollanam,Kyonggi,Kang-won,Kyonggi,Kang-won,Kyonggi,Kang-won,Chungchongbuk,Kyongsangbuk,Chollanam,Kyongsangbuk,Kyonggi,Kyongsangnam,Kyonggi,Chungchongnam,Kyongsangnam,Kyongsangbuk,Chungchongnam,Kyonggi,Chollabuk,Chungchongbuk,Chungchongnam,Kyonggi,Kyongsangnam,Chungchongnam,Kyongsangbuk,Kyongsangnam,Kyongsangbuk,Chungchongnam,Chollanam,Kyongsangnam,Kyonggi,Chollabuk,Kyongsangbuk,Kyongsangnam,Kyonggi,Chollanam,Chollabuk,Kang-won,Kyongsangbuk |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
```

{% endcode %}

{% code title="DISTINCT 키워드로 중복을 회피한 경우" %}

```sql
mysql> select group_concat(distinct district) from city where countrycode = 'KOR';
+------------------------------------------------------------------------------------------------------------------------------------------+
| group_concat(distinct district)                                                                                                          |
+------------------------------------------------------------------------------------------------------------------------------------------+
| Cheju,Chollabuk,Chollanam,Chungchongbuk,Chungchongnam,Inchon,Kang-won,Kwangju,Kyonggi,Kyongsangbuk,Kyongsangnam,Pusan,Seoul,Taegu,Taejon |
+------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
```

{% endcode %}

## 데이터를 그룹으로 나누는 GROUP BY

대상이 되는 데이터를 몇 개의 그룹으로 나눠서 집약하는 것도 가능하다. 예를 들어, '행정구역(district) 마다', '국가(country) 마다' 집약하는 식이다.

```sql
SELECT ~ FROM 테이블명 GROUP BY 열명1 [ , 열명2, ... ]
```

GROUP BY 로 지정한 열을 '집약 키' 또는 '그룹화 키' 로 부르며, 복수 열을 콤마로 구분해 지정할 수 도 있다.

{% code title="GROUP BY 없을 경우" %}

```sql
mysql> select count(*) from city where countrycode = 'KOR';
+----------+
| count(*) |
+----------+
|       70 |
+----------+
1 row in set (0.00 sec)
```

{% endcode %}

{% code title="GROUP BY 있는 경우" %}

```sql
mysql> select district, count(*) from city where countrycode = 'KOR' group by district;
+---------------+----------+
| district      | count(*) |
+---------------+----------+
| Seoul         |        1 |
| Pusan         |        1 |
| Inchon        |        1 |
| Taegu         |        1 |
| Taejon        |        1 |
| Kwangju       |        1 |
| Kyongsangnam  |       11 |
| Kyonggi       |       18 |
| Chollabuk     |        6 |
| Chungchongbuk |        3 |
| Kyongsangbuk  |       10 |
| Chungchongnam |        6 |
| Cheju         |        1 |
| Chollanam     |        5 |
| Kang-won      |        4 |
+---------------+----------+
15 rows in set (0.00 sec)
```

{% endcode %}

## 나눈 그룹에 조건 추가

그룹으로 나눠서 집약한 값에 대해 조건을 설정하려면 어떻게 해야 할까?

'조건'이 있다면 WHERE 구문에 조건을 추가하고 싶지만 오류가 발생한다. COUNT 같은 **집약함수를 작성할 수 있는 경우는 SELECT와 ORDER BY, HAVING 뿐이다.**

```sql
mysql> select district, count(*) from city where countrycode = 'KOR' and count(*) = 4 group by district;
ERROR 1111 (HY000): Invalid use of group function
```

## 집약한 결과에 조건 지정

그룹마다 집약한 값을 조건으로 선택하고 싶다면 HAVING 뒤에 조건을 지정해야 한다.

```sql
SELECT ~ FROM ~ GROUP BY ~ HAVING 그룹의 값에 대한 조건 
```

```sql
mysql> select district, count(*) from city where countrycode = 'KOR' group by district having count(*) = 6;
+---------------+----------+
| district      | count(*) |
+---------------+----------+
| Chollabuk     |        6 |
| Chungchongnam |        6 |
+---------------+----------+
2 rows in set (0.00 sec)
```

또한, 앞에서 말한대로 SELECT와 ORDER BY 에도 집약함수를 기술 할 수 있다.&#x20;

```sql
mysql> select district, count(*) from city where countrycode = 'KOR' group by district having count(*) > 6 order by count(*) desc;
+--------------+----------+
| district     | count(*) |
+--------------+----------+
| Kyonggi      |       18 |
| Kyongsangnam |       11 |
| Kyongsangbuk |       10 |
+--------------+----------+
3 rows in set (0.00 sec)
```

SELECT 문의 작성 순서는 다음과 같다.

```sql
SELECT ~ FROM ~ GROUP BY ~ HAVING ~ ORDER BY ~
```
