> ## Documentation Index
> Fetch the complete documentation index at: https://villagesql.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# MySQL 셀프 조인

> MySQL 테이블을 자기 자신과 조인해 자신의 행끼리 비교하는 방법, 쿼리에 2개의 별칭이 필요한 이유, 그리고 모든 쌍이 두 번 나타나지 않게 막는 조건입니다.

> [card] [VillageSQL is a drop-in replacement for MySQL with extensions.](https://villagesql.com/docs/en/8.4/stable/install-server.md)
>
> All examples on this page work on VillageSQL. Install Now →

셀프 조인은 같은 쿼리에서 1개의 테이블을 두 번 읽어서, 그 행들을 서로 비교할 수 있게 합니다. 쌍에 관한 질문에 답하는 방법입니다: 어떤 행들이 값을 공유하는지, 어떤 행이 어떤 행보다 큰지 같은 것입니다.

시작하기 전에 `mysql -u root -p sakila`로 클라이언트를 여세요.

## 셀프 조인의 동작 방식

```sql theme={null}
SELECT FIRST_ALIAS.COLUMN_NAME, SECOND_ALIAS.COLUMN_NAME
FROM TABLE_NAME AS FIRST_ALIAS
JOIN TABLE_NAME AS SECOND_ALIAS
  ON FIRST_ALIAS.COLUMN_NAME = SECOND_ALIAS.COLUMN_NAME;
```

`TABLE_NAME`을 테이블로, `FIRST_ALIAS`와 `SECOND_ALIAS`를 그 테이블의 서로 다른 2개의 이름으로, 각 `COLUMN_NAME`을 비교하는 열로 바꾸세요.

조인의 다른 부분은 아무것도 바뀌지 않습니다. 서버는 양쪽이 하나의 테이블이라는 것을 전혀 모르고, 다른 어떤 테이블 쌍과 똑같이 다룹니다.

## 별칭은 선택 사항이 아닙니다

별칭이 없으면 쿼리는 2개의 것을 모두 `actor`라고 부르고 둘을 구별할 수 없습니다.

```sql theme={null}
SELECT first_name FROM actor JOIN actor ON actor.last_name = actor.last_name LIMIT 1;
```

```text theme={null}
ERROR 1066 (42000): Not unique table/alias: 'actor'
```

`ERROR 1066`은 서버가 각 쪽에 이름이 필요하다고 말하는 것입니다.

## 예제

### 값을 공유하는 행

Sakila의 일부 배우는 성을 공유합니다. 이 쿼리는 그들 각각을 나머지와 짝지어 줍니다.

```sql theme={null}
SELECT a1.first_name, a1.last_name, a2.first_name AS also_named
FROM actor AS a1
JOIN actor AS a2 ON a1.last_name = a2.last_name AND a1.actor_id < a2.actor_id
ORDER BY a1.last_name, a1.first_name, a2.first_name;
```

```text theme={null}
+-------------+-------------+-------------+
| first_name  | last_name   | also_named  |
+-------------+-------------+-------------+
| CHRISTIAN   | AKROYD      | DEBBIE      |
| CHRISTIAN   | AKROYD      | KIRSTEN     |
| KIRSTEN     | AKROYD      | DEBBIE      |
| CUBA        | ALLEN       | KIM         |
| CUBA        | ALLEN       | MERYL       |
| KIM         | ALLEN       | MERYL       |
...
+-------------+-------------+-------------+
108 rows in set (0.00 sec)
```

3명의 배우가 AKROYD라는 성을 쓰고, 그들 사이에 3개의 쌍이 만들어집니다.

### 숫자로 행 비교하기

같은 형태가 "어떤 영화가 어떤 영화와 정확히 같은 길이인가"에 답합니다. 이 쿼리는 카탈로그에서 가장 긴 영화로 범위를 좁힙니다.

```sql theme={null}
SELECT f1.title, f2.title AS same_length, f1.length
FROM film AS f1
JOIN film AS f2 ON f1.length = f2.length AND f1.film_id < f2.film_id
WHERE f1.length = 185
ORDER BY f1.title, f2.title;
```

```text theme={null}
+--------------------+--------------------+--------+
| title              | same_length        | length |
+--------------------+--------------------+--------+
| CHICAGO NORTH      | CONTROL ANTHEM     |    185 |
| CHICAGO NORTH      | DARN FORRESTER     |    185 |
| CHICAGO NORTH      | GANGS PRIDE        |    185 |
...
+--------------------+--------------------+--------+
45 rows in set (0.00 sec)
```

10편의 영화가 185분이고, 45는 10개의 것으로 만들 수 있는 쌍의 수입니다.

## 두 번째 조건이 하는 일

`a1.actor_id < a2.actor_id`가 각 쌍을 한 번만 유지하고 배우가 자기 자신과 짝지어지지 않게 막는 것입니다. 이것을 빼면 같은 쿼리가 다른 질문에 답합니다.

```sql theme={null}
SELECT a1.first_name, a1.last_name, a2.first_name AS also_named
FROM actor AS a1
JOIN actor AS a2 ON a1.last_name = a2.last_name
ORDER BY a1.last_name, a1.first_name, a2.first_name;
```

```text theme={null}
+-------------+--------------+-------------+
| first_name  | last_name    | also_named  |
+-------------+--------------+-------------+
| CHRISTIAN   | AKROYD       | CHRISTIAN   |
| CHRISTIAN   | AKROYD       | DEBBIE      |
| CHRISTIAN   | AKROYD       | KIRSTEN     |
| DEBBIE      | AKROYD       | CHRISTIAN   |
| DEBBIE      | AKROYD       | DEBBIE      |
| DEBBIE      | AKROYD       | KIRSTEN     |
...
+-------------+--------------+-------------+
416 rows in set (0.00 sec)
```

108개가 아니라 416개의 행이고, 2종류의 행이 끼어들었습니다. `CHRISTIAN AKROYD`는 자기 자신과 짝지어졌는데, 자신의 행이 `a1.last_name = a2.last_name`을 만족하기 때문입니다. 그리고 `CHRISTIAN`과 `DEBBIE`가 나온 다음 `DEBBIE`와 `CHRISTIAN`이 나오는데, 이것은 같은 쌍을 거꾸로 쓴 것입니다.

id를 `<`로 비교하면 둘 다 한 번에 해결됩니다. 어떤 id도 자기 자신보다 작지 않으므로 행이 자기 자신과 일치하는 것을 막고, 진짜 쌍 각각의 1가지 배열만 유지합니다. 셀프 조인이 쌍을 찾을 때는 언제나 `<`를 쓰세요.

## 요약

* 1개의 테이블의 행을 서로 비교하려면 셀프 조인을 쓰세요.
* 테이블에 2개의 별칭을 주세요. 별칭이 없으면 `ERROR 1066`이 납니다.
* 각 쌍을 한 번만 원할 때는 2개의 별칭의 기본 키를 `<`로 비교하세요.
* 막지 않으면 행이 자기 자신과 일치한다고 예상하세요.

## 함께 보기

* [테이블 별칭](https://villagesql.com/docs/ko/tutorial/table-aliases.md) — 이 쿼리가 의존하는 이름 붙이기
* [INNER JOIN](https://villagesql.com/docs/ko/tutorial/inner-join.md) — 셀프 조인이 그 특수한 경우인 조인
* [조인의 동작 방식](https://villagesql.com/docs/ko/tutorial/joins.md) — 다른 종류 사이에서 이것의 위치
* [MySQL JOIN 성능과 흔한 실수](https://villagesql.com/docs/ko/guides/joins.md) — 큰 테이블에서 셀프 조인의 비용


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.