카테고리:

쿼리 구문

JOIN

JOIN 작업은 두 테이블(또는 뷰나 테이블 함수와 같은 다른 테이블 유사 소스)의 행을 결합하여, 쿼리에 사용할 수 있는 결합된 새 행을 만듭니다. 조인에 대한 개념 설명은 조인 관련 작업하기 을 참조하십시오.

이 항목에서는 FROM 절에서 JOIN 구문을 사용하는 방법에 대해 설명합니다. JOIN 하위 절은 한 테이블의 행을 다른 테이블의 해당 행과 관련시키는 방법을 (명시적 또는 암시적으로) 지정합니다.

테이블을 조인하는 데 권장되는 방법은 FROM 절의 ON 하위 절과 함께 JOIN 을 사용하는 것이지만, 테이블을 조인하는 다른 방법은 WHERE 절을 사용하는 것입니다. 자세한 내용은 WHERE 절에 대한 설명서를 참조하십시오.

구문

다음 중 하나를 사용하십시오.

SELECT ...
FROM <object_ref1> [
                     {
                       INNER
                       | { LEFT | RIGHT | FULL } [ OUTER ]
                     }
                   ]
                   JOIN <object_ref2>
  [ ON <condition> ]
[ ... ]
Copy
SELECT *
FROM <object_ref1> [
                     {
                       INNER
                       | { LEFT | RIGHT | FULL } [ OUTER ]
                     }
                   ]
                   JOIN <object_ref2>
  [ USING( <column_list> ) ]
[ ... ]
Copy
SELECT ...
FROM <object_ref1> [
                     {
                       | NATURAL [ { LEFT | RIGHT | FULL } [ OUTER ] ]
                       | CROSS
                     }
                   ]
                   JOIN <object_ref2>
[ ... ]
Copy
object_ref1object_ref2

각 오브젝트 참조는 테이블 또는 테이블과 유사한 데이터 소스입니다.

JOIN

JOIN 키워드를 사용하여, 테이블을 조인해야 함을 지정하십시오. JOIN 을 다른 조인 관련 키워드(예: INNER 또는 OUTER)와 결합하여 조인 유형을 지정하십시오.

조인의 의미 체계는 다음과 같습니다(간결함을 위해 이 항목에서는 o1o2 에 대해 각각 object_ref1object_ref2 를 사용함).

조인 유형

의미 체계

o1 INNER JOIN o2

o1 의 각 행의 경우, ON condition 하위 절에 따라 일치하는 o2 의 각 행에 대해 행이 생성됩니다. (쉼표를 사용하여 내부 조인을 지정할 수도 있습니다. 예를 들어, 아래의 예 섹션을 참조하십시오.) ON 절 없이 INNER JOIN 을 사용하는 경우(또는 WHERE 절 없이 쉼표를 사용하는 경우), 결과는 CROSS JOIN 을 사용하는 것과 동일합니다. 즉, 데카르트 곱(o1 의 모든 행은 o2 의 모든 행과 쌍을 이룸)입니다.

o1 LEFT OUTER JOIN o2

내부 조인의 결과는 o1 에 일치 항목이 없는 o2 의 각 행에 대한 행으로 증가됩니다. o2 를 참조하는 결과 열에 null이 포함되어 있습니다.

o1 RIGHT OUTER JOIN o2

내부 조인의 결과는 o2 에 일치 항목이 없는 o1 의 각 행에 대한 행으로 증가됩니다. o1 를 참조하는 결과 열에 null이 포함되어 있습니다.

o1 FULL OUTER JOIN o2

조인된 모든 행, 그리고 일치하지 않는 왼쪽 행(오른쪽이 null로 확장됨)에 대한 행 하나, 그리고 일치하지 않는 오른쪽 행(왼쪽이 null로 확장됨)에 대한 행 하나를 반환합니다.

o1 CROSS JOIN o2

o1o2 의 가능한 모든 행 조합(즉, 데카르트 곱)의 경우, 조인된 테이블에는 o1 의 모든 열에 이어 o2 의 모든 열로 구성된 행이 포함됩니다. CROSS JOINON condition 절과 결합할 수 없습니다. 그러나 WHERE 절을 사용하여 결과를 필터링할 수 있습니다.

o1 NATURAL JOIN o2

NATURAL JOIN 은 공통 열이 출력에 한 번만 포함된다는 점을 제외하고는, 두 테이블의 공통 열에 대한 명시적 JOIN 과 동일합니다. (자연 조인은 이름이 같되 테이블이 다른 열에 해당 데이터가 포함되어 있다고 가정합니다.) 몇 가지 예는 아래의 예 섹션을 참조하십시오. NATURAL JOINOUTER JOIN 과 결합할 수 있습니다. JOIN 조건이 이미 내포되어 있으므로 NATURAL JOINON condition 절과 결합할 수 없습니다. 그러나 WHERE 절을 사용하여 결과를 필터링할 수 있습니다.

참고 항목:

래터럴 조인

기본값: INNER JOIN

INNER 또는 OUTER 를 지정하지 않고 JOIN 단어를 사용하는 경우, JOIN 은 내부 조인입니다.

ON condition

일치하는 것으로 간주되는 JOIN 의 두 측면에서 행을 정의하는 부울 식입니다. 예를 들면 다음과 같습니다.

ON object_ref2.id_number = object_ref1.id_number
Copy

조건은 WHERE 절 문서에서 더 자세히 설명합니다.

ON 절은 CROSS JOIN 에는 금지됩니다.

ON 절은 NATURAL JOIN 에 필요하지 않으며 금지됩니다. 조인 열은 내포됩니다.

다른 조인의 경우, ON 절은 선택 사항입니다. 그러나 ON 절을 생략하면 데카르트 곱이 생성됩니다(object_ref1 의 모든 행은 object_ref2 의 모든 행과 쌍을 이룸). 데카르트 곱은 매우 많은 양의 출력을 생성할 수 있으며, 그중 거의 모두는 실제로는 관련되지 않은 행 쌍으로 구성됩니다. 이는 많은 리소스를 사용하며, 사용자 오류인 경우가 많습니다.

USING( <column_list> )

조인되는 두 테이블 사이의 공통 열 목록입니다. 이러한 열은 조인 열로 사용됩니다. 열은 조인되는 각 테이블에서 동일한 이름과 의미를 가져야 합니다.

예를 들어, SQL 문에 다음이 포함되어 있다고 가정합니다.

... o1 JOIN o2
    USING (key_column)
Copy

간단한 경우에 이는 다음과 같습니다.

... o1 JOIN o2
    ON o2.key_column = o1.key_column
Copy

표준 JOIN 구문에서 프로젝션 목록(SELECT 키워드 뒤에 있는 열과 기타 식의 목록)은 《*》입니다. 이로 인해 쿼리가 key_column 을 정확히 한 번 반환합니다. 열은 다음 순서로 반환됩니다.

  • USING 절의 열(지정된 순서대로 반환).

  • USING 절에 지정되지 않은 왼쪽 테이블 열.

  • USING 절에 지정되지 않은 오른쪽 테이블 열.

표준 및 비표준 사용법의 예는 아래 예를 참조하십시오.

사용법 노트

  • SQL UDTF 이외의 테이블 함수에는 다음 제한 사항이 적용됩니다.

    • 측면 테이블 함수(SQL UDTF 제외)에는 ON, USING 또는 NATURAL JOIN 절을 지정할 수 없습니다.

      예를 들어 다음 구문은 허용되지 않습니다.

      SELECT ... FROM my_table
        JOIN TABLE(FLATTEN(input=>[col_a]))
        ON ... ;
      
      Copy
      SELECT ... FROM my_table
        INNER JOIN TABLE(FLATTEN(input=>[col_a]))
        ON ... ;
      
      Copy
      SELECT ... FROM my_table
        JOIN TABLE(my_js_udtf(col_a))
        ON ... ;
      
      Copy
      SELECT ... FROM my_table
        INNER JOIN TABLE(my_js_udtf(col_a))
        ON ... ;
      
      Copy
    • 테이블 함수(SQL UDTF 제외)에 대한 외부 측면 조인에는 ON, USING 또는 NATURAL JOIN 절을 지정할 수 없습니다.

      예를 들어 다음 구문은 허용되지 않습니다.

      SELECT ... FROM my_table
        LEFT JOIN TABLE(FLATTEN(input=>[a]))
        ON ... ;
      
      Copy
      SELECT ... FROM my_table
        FULL JOIN TABLE(FLATTEN(input=>[a]))
        ON ... ;
      
      Copy
      SELECT ... FROM my_table
        LEFT JOIN TABLE(my_js_udtf(a))
        ON ... ;
      
      Copy
      SELECT ... FROM my_table
        FULL JOIN TABLE(my_js_udtf(a))
        ON ... ;
      
      Copy
    • 위에서 이 구문을 사용하면 다음 오류가 발생합니다.

      000002 (0A000): Unsupported feature
        'lateral table function called with OUTER JOIN syntax
         or a join predicate (ON clause)'
      
    • JOIN 키워드가 아닌 쉼표를 사용하는 경우에는 이러한 제한 사항이 적용되지 않습니다.

      SELECT ... FROM my_table,
        TABLE(FLATTEN(input=>[col_a]))
        ON ... ;
      
      Copy

많은 JOIN 예에서는 t1t2 라는 두 개의 테이블을 사용합니다. 이 테이블과 해당 데이터는 아래와 같이 만들어집니다.

CREATE TABLE t1 (col1 INTEGER);
CREATE TABLE t2 (col1 INTEGER);
Copy
INSERT INTO t1 (col1) VALUES 
   (2),
   (3),
   (4);
INSERT INTO t2 (col1) VALUES 
   (1),
   (2),
   (2),
   (3);
Copy

내부 조인:

SELECT t1.col1, t2.col1
    FROM t1 INNER JOIN t2
        ON t2.col1 = t1.col1
    ORDER BY 1,2;
+------+------+
| COL1 | COL1 |
|------+------|
|    2 |    2 |
|    2 |    2 |
|    3 |    3 |
+------+------+
Copy

이는 왼쪽 외부 조인을 보여줍니다. 테이블 t2에 일치하는 행이 없는 테이블 t1의 행에 대한 NULL 값에 유의하십시오.

SELECT t1.col1, t2.col1
    FROM t1 LEFT OUTER JOIN t2
        ON t2.col1 = t1.col1
    ORDER BY 1,2;
+------+------+
| COL1 | COL1 |
|------+------|
|    2 |    2 |
|    2 |    2 |
|    3 |    3 |
|    4 | NULL |
+------+------+
Copy

이는 오른쪽 외부 조인을 보여줍니다. 테이블 t2에 일치하는 행이 없는 테이블 t1의 행에 대한 NULL 값에 유의하십시오.

SELECT t1.col1, t2.col1
    FROM t1 RIGHT OUTER JOIN t2
        ON t2.col1 = t1.col1
    ORDER BY 1,2;
+------+------+
| COL1 | COL1 |
|------+------|
|    2 |    2 |
|    2 |    2 |
|    3 |    3 |
| NULL |    1 |
+------+------+
Copy

이는 전체 외부 조인을 보여줍니다. 각 테이블에는 다른 테이블에서 일치하는 행이 없는 행이 있기 때문에 출력에는 다음과 같이 NULL 값이 있는 두 개의 행이 포함된다는 것에 유의하십시오.

SELECT t1.col1, t2.col1
    FROM t1 FULL OUTER JOIN t2
        ON t2.col1 = t1.col1
    ORDER BY 1,2;
+------+------+
| COL1 | COL1 |
|------+------|
|    2 |    2 |
|    2 |    2 |
|    3 |    3 |
|    4 | NULL |
| NULL |    1 |
+------+------+
Copy

다음은 데카르트 곱을 생성하는 크로스 조인의 예입니다. 크로스 조인에는 ON 절이 없음에 유의하십시오.

SELECT t1.col1, t2.col1
    FROM t1 CROSS JOIN t2
    ORDER BY 1, 2;
+------+------+
| COL1 | COL1 |
|------+------|
|    2 |    1 |
|    2 |    2 |
|    2 |    2 |
|    2 |    3 |
|    3 |    1 |
|    3 |    2 |
|    3 |    2 |
|    3 |    3 |
|    4 |    1 |
|    4 |    2 |
|    4 |    2 |
|    4 |    3 |
+------+------+
Copy

크로스 조인은 아래 예와 같이 WHERE 절로 필터링할 수 있습니다.

SELECT t1.col1, t2.col1
    FROM t1 CROSS JOIN t2
    WHERE t2.col1 = t1.col1
    ORDER BY 1, 2;
+------+------+
| COL1 | COL1 |
|------+------|
|    2 |    2 |
|    2 |    2 |
|    3 |    3 |
+------+------+
Copy

이는 자연 조인의 예입니다. 이렇게 할 경우, 출력에 조인 열의 두 번째 복사본이 포함되지 않는다는 점을 제외하고는, 해당 내부 조인과 동일한 출력이 다음과 같이 생성됩니다.

CREATE OR REPLACE TABLE d1 (
  id number,
  name string
  );
+--------------------------------+
| status                         |
|--------------------------------|
| Table D1 successfully created. |
+--------------------------------+
INSERT INTO d1 (id, name) VALUES
  (1,'a'),
  (2,'b'),
  (4,'c');
+-------------------------+
| number of rows inserted |
|-------------------------|
|                       3 |
+-------------------------+
CREATE OR REPLACE TABLE d2 (
  id number,
  value string
  );
+--------------------------------+
| status                         |
|--------------------------------|
| Table D2 successfully created. |
+--------------------------------+
INSERT INTO d2 (id, value) VALUES
  (1,'xx'),
  (2,'yy'),
  (5,'zz');
+-------------------------+
| number of rows inserted |
|-------------------------|
|                       3 |
+-------------------------+
SELECT *
    FROM d1 NATURAL INNER JOIN d2
    ORDER BY id;
+----+------+-------+
| ID | NAME | VALUE |
|----+------+-------|
|  1 | a    | xx    |
|  2 | b    | yy    |
+----+------+-------+
Copy

자연 조인은 외부 조인과 결합될 수 있습니다. 예를 들면 다음과 같습니다.

SELECT *
  FROM d1 NATURAL FULL OUTER JOIN d2
  ORDER BY ID;
+----+------+-------+
| ID | NAME | VALUE |
|----+------+-------|
|  1 | a    | xx    |
|  2 | b    | yy    |
|  4 | c    | NULL  |
|  5 | NULL | zz    |
+----+------+-------+
Copy

조인은 FROM 절에서 결합될 수 있습니다. 다음 코드는 세 번째 테이블을 만든 다음 FROM 절에서 두 개의 JOIN을 연결합니다.

CREATE TABLE t3 (col1 INTEGER);
INSERT INTO t3 (col1) VALUES 
   (2),
   (6);
Copy
SELECT t1.*, t2.*, t3.*
  FROM t1
     LEFT OUTER JOIN t2 ON (t1.col1 = t2.col1)
     RIGHT OUTER JOIN t3 ON (t3.col1 = t2.col1)
  ORDER BY t1.col1;
+------+------+------+
| COL1 | COL1 | COL1 |
|------+------+------|
|    2 |    2 |    2 |
|    2 |    2 |    2 |
| NULL | NULL |    6 |
+------+------+------+
Copy

이러한 쿼리에서 결과는 왼쪽에서 오른쪽으로 발생하는 조인을 기반으로 결정됩니다(단, 다른 조인 순서가 동일 결과를 생성하는 경우, 옵티마이저가 조인을 재정렬할 수 있음). 오른쪽 외부 조인이 왼쪽 외부 조인보다 먼저 발생해야 하는 경우, 쿼리는 다음과 같이 작성할 수 있습니다.

SELECT t1.*, t2.*, t3.*
  FROM t1
     LEFT OUTER JOIN
     (t2 RIGHT OUTER JOIN t3 ON (t3.col1 = t2.col1))
     ON (t1.col1 = t2.col1)
  ORDER BY t1.col1;
+------+------+------+
| COL1 | COL1 | COL1 |
|------+------+------|
|    2 |    2 |    2 |
|    2 |    2 |    2 |
|    3 | NULL | NULL |
|    4 | NULL | NULL |
+------+------+------+
Copy

아래의 두 가지 예는 USING 절의 표준(ISO 9075) 및 비표준 사용법을 보여줍니다. 둘 다 Snowflake에서 지원됩니다.

이 첫 번째 예는 표준 사용법을 보여줍니다. 특히 프로젝션 목록에는 정확히 《*》가 포함됩니다. 예시 쿼리가 두 개의 테이블을 조인하고, 각 테이블에 하나의 열이 있고, 쿼리가 모든 열을 요청하더라도 출력에는 두 개의 열이 아니라 하나의 열이 포함됩니다.

WITH
    l AS (
         SELECT 'a' AS userid
         ),
    r AS (
         SELECT 'b' AS userid
         )
  SELECT *
    FROM l LEFT JOIN r USING(userid)
;
+--------+
| USERID |
|--------|
| a      |
+--------+
Copy

다음 예에서는 비표준 사용법을 보여줍니다. 프로젝션 목록에는 《*》가 아닌 다른 항목이 포함됩니다. 출력에는 두 개의 열이 포함되며 두 번째 열에는 두 번째 테이블의 값 또는 NULL이 포함됩니다.

WITH
    l AS (
         SELECT 'a' AS userid
       ),
    r AS (
         SELECT 'b' AS userid
         )
  SELECT l.userid as UI_L,
         r.userid as UI_R
    FROM l LEFT JOIN r USING(userid)
;
+------+------+
| UI_L | UI_R |
|------+------|
| a    | NULL |
+------+------+
Copy