> ## 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 CROSS JOIN

> MySQL CROSS JOIN이 한 테이블의 모든 행을 다른 테이블의 모든 행과 짝짓는 방법, 그것이 만들어내는 행의 수, 그리고 의도한 것과 실수를 구분하는 방법입니다.

> [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 →

`CROSS JOIN`은 한 테이블의 모든 행을 다른 테이블의 모든 행과 짝짓습니다. 아무것도 일치시키지 않으므로 `ON` 조건을 쓰지 않습니다. 모든 조합을 원할 때 요청하는 조인이고, `ON` 절을 빠뜨렸을 때 실수로 얻게 되는 조인입니다.

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

## CROSS JOIN의 동작 방식

```sql theme={null}
SELECT COLUMN_LIST
FROM FIRST_TABLE
CROSS JOIN SECOND_TABLE;
```

`COLUMN_LIST`를 원하는 열로, `FIRST_TABLE`과 `SECOND_TABLE`을 결합할 테이블로 바꾸세요. 결과는 가능한 모든 짝마다 1개의 행을 담으므로, 그 크기는 첫 번째 테이블의 행 수에 두 번째 테이블의 행 수를 곱한 것입니다. 6개 행과 2개 행을 교차하면 12개가 됩니다.

## 예제

### 모든 조합

Sakila에는 6개의 언어와 2개의 매장이 있습니다.

```sql theme={null}
SELECT l.name, s.store_id
FROM language AS l
CROSS JOIN store AS s
ORDER BY l.name, s.store_id;
```

```text theme={null}
+----------+----------+
| name     | store_id |
+----------+----------+
| English  |        1 |
| English  |        2 |
| French   |        1 |
| French   |        2 |
| German   |        1 |
| German   |        2 |
| Italian  |        1 |
| Italian  |        2 |
| Japanese |        1 |
| Japanese |        2 |
| Mandarin |        1 |
| Mandarin |        2 |
+----------+----------+
12 rows in set (0.00 sec)
```

모든 언어가 매장마다 한 번씩 나타납니다. 여기의 어떤 것도 매장이 그 언어의 영화를 갖추고 있다고 말하지 않습니다: 행은 조합이지 데이터에 관한 사실이 아닙니다. 그것이 이 쿼리의 요점입니다. 이런 격자는 무언가 일어났든 아니든 모든 짝마다 행을 원할 때의 출발 형태입니다.

### 쉼표는 더 오래된 표기입니다

```sql theme={null}
SELECT l.name, s.store_id
FROM language AS l, store AS s
ORDER BY l.name, s.store_id;
```

```text theme={null}
+----------+----------+
| name     | store_id |
+----------+----------+
| English  |        1 |
| English  |        2 |
| French   |        1 |
| French   |        2 |
| German   |        1 |
| German   |        2 |
| Italian  |        1 |
| Italian  |        2 |
| Japanese |        1 |
| Japanese |        2 |
| Mandarin |        1 |
| Mandarin |        2 |
+----------+----------+
12 rows in set (0.00 sec)
```

같은 12개의 행입니다. `FROM`에서 2개의 테이블 사이에 있는 쉼표는 교차 조인입니다. 오래된 SQL에서 만나게 될 텐데, 일치 조건은 흔히 아래쪽 `WHERE`에 있으며, 이것은 동작하지만 어떤 종류의 조인을 읽고 있는지 숨깁니다.

쉼표는 `JOIN`보다 느슨하게 결합하므로, `ON` 절은 쉼표 반대편에 있는 테이블에 닿을 수 없습니다. 실제 쿼리에서 2가지 표기가 함께 나타나기도 하며, 그럴 때 잘못되는 것이 이것입니다.

```sql theme={null}
SELECT COUNT(*) FROM film f, language l JOIN store s ON s.store_id = f.language_id;
```

```text theme={null}
ERROR 1054 (42S22): Unknown column 'f.language_id' in 'on clause'
```

교차 조인을 의도할 때는 `CROSS JOIN`이라고 쓰고, 쿼리 하나에는 한 가지 표기만 쓰세요.

키워드가 규칙을 강제하지도 않습니다. MySQL은 `CROSS JOIN`에 붙은 `ON` 절을 받아들이고 그다음 `INNER JOIN`처럼 동작하므로, 쿼리의 단어는 어떤 조인을 얻었는지에 대한 증거가 아닙니다.

```sql theme={null}
SELECT COUNT(*) AS rows_returned
FROM film AS f CROSS JOIN language AS l ON f.language_id = l.language_id;
```

```text theme={null}
+---------------+
| rows_returned |
+---------------+
|          1000 |
+---------------+
1 row in set (0.00 sec)
```

6,000이 아니라 1,000입니다: 모든 영화가 자기 언어와 일치했습니다. 조인이 하는 일을 알려면 키워드가 아니라 `ON` 절을 읽으세요.

## 숫자는 빠르게 커집니다

12개 행은 무해합니다. 평소에 쿼리하는 테이블에 같은 연산을 하면 그렇지 않습니다.

```sql theme={null}
SELECT f.title, l.name
FROM film AS f
CROSS JOIN language AS l
ORDER BY f.title, l.name;
```

```text theme={null}
+-----------------------------+----------+
| title                       | name     |
+-----------------------------+----------+
| ACADEMY DINOSAUR            | English  |
| ACADEMY DINOSAUR            | French   |
| ACADEMY DINOSAUR            | German   |
...
+-----------------------------+----------+
6000 rows in set (0.01 sec)
```

1,000편의 영화 곱하기 6개의 언어는 6,000개의 행이고, 이제 영화마다 6개 언어를 모두 가진 것으로 나옵니다. 10,000개 행짜리 테이블 2개를 교차하면 답은 1억 개의 행이 되며, 즉시 끝났어야 할 쿼리가 누군가 죽일 때까지 실행되는 방식이 이것입니다.

MySQL은 `ON` 절이 없는 `INNER JOIN`을 받아들이고 이것으로 취급합니다. 그래서 조인이 의심스럽게 딱 떨어지고 의심스럽게 큰 숫자를 반환하면, 가장 먼저 확인할 것은 빠진 `ON`입니다. [INNER JOIN](https://villagesql.com/docs/ko/tutorial/inner-join.md) 레슨이 그 실수를 보여 줍니다.

## 요약

* 한 테이블의 모든 행을 다른 테이블의 모든 행과 짝지으려면 `CROSS JOIN`을 사용하세요.
* 아무것도 일치시키지 않으므로 `ON` 절을 쓰지 마세요.
* MySQL이 `CROSS JOIN ... ON`을 어쨌든 받아들이고 내부 조인으로 취급한다고 예상하세요.
* 실행하기 전에 두 테이블의 행 수를 곱해서 크기를 알아 두세요.
* `FROM`에서 테이블 사이의 쉼표를 교차 조인으로 읽고, 쿼리 하나에는 1가지 표기만 쓰세요.
* 조인이 딱 떨어지는 큰 수의 행을 반환하면 빠진 `ON`을 의심하세요.

## 함께 보기

* [조인의 동작 방식](https://villagesql.com/docs/ko/tutorial/joins.md) — 다른 종류들 사이에서 이것이 차지하는 자리
* [INNER JOIN](https://villagesql.com/docs/ko/tutorial/inner-join.md) — 대신 행을 일치시키는 조인
* [테이블 별칭](https://villagesql.com/docs/ko/tutorial/table-aliases.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.