[sql] SQL JOIN-WHERE 절과 ON 절

읽은 후에 는 명시 적 vs 암시 적 SQL 조인 의 복제본 이 아닙니다 . 대답은 관련이있을 수도 있고 같은 내용 일 수도 있지만 질문 은 다릅니다.


차이점은 무엇이며 각각 어떻게해야합니까?

이론을 올바르게 이해하면 쿼리 최적화 프로그램에서 두 가지를 모두 사용할 수 있어야합니다.



답변

그들은 같은 것이 아닙니다.

다음 쿼리를 고려하십시오.

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID
WHERE Orders.ID = 12345

SELECT *
FROM Orders
LEFT JOIN OrderLines ON OrderLines.OrderID=Orders.ID
    AND Orders.ID = 12345

첫 번째는 주문 번호에 대한 주문 및 해당하는 경우 해당 라인을 리턴합니다 12345. 두 번째는 모든 주문을 반환하지만 주문 12345과 관련된 줄만 있습니다.

를 사용하면 INNER JOIN절이 사실상 동일합니다. 그러나 기능적으로 동일하기 때문에 동일한 결과를 생성한다고해서 두 종류의 절이 동일한 의미 적 의미를 갖는 것은 아닙니다.


답변

  • 내부 조인에는 중요하지 않습니다
  • 외부 조인에 관한 사항

    ㅏ. WHERE조항 : 가입 . 가입이 완료된 후 레코드가 필터링됩니다.

    비. ON조항- 가입 하기 전 . 오른쪽 테이블의 레코드는 조인하기 전에 필터링됩니다. 결과에서 OUTER 조인 이후로 null로 끝날 수 있습니다.

: 아래 표를 고려하십시오.

    1. documents:
     | id    | name        |
     --------|-------------|
     | 1     | Document1   |
     | 2     | Document2   |
     | 3     | Document3   |
     | 4     | Document4   |
     | 5     | Document5   |


    2. downloads:
     | id   | document_id   | username |
     |------|---------------|----------|
     | 1    | 1             | sandeep  |
     | 2    | 1             | simi     |
     | 3    | 2             | sandeep  |
     | 4    | 2             | reya     |
     | 5    | 3             | simi     |

a) 내부 WHERE조항 :

  SELECT documents.name, downloads.id
    FROM documents
    LEFT OUTER JOIN downloads
      ON documents.id = downloads.document_id
    WHERE username = 'sandeep'

 For above query the intermediate join table will look like this.

    | id(from documents) | name         | id (from downloads) | document_id | username |
    |--------------------|--------------|---------------------|-------------|----------|
    | 1                  | Document1    | 1                   | 1           | sandeep  |
    | 1                  | Document1    | 2                   | 1           | simi     |
    | 2                  | Document2    | 3                   | 2           | sandeep  |
    | 2                  | Document2    | 4                   | 2           | reya     |
    | 3                  | Document3    | 5                   | 3           | simi     |
    | 4                  | Document4    | NULL                | NULL        | NULL     |
    | 5                  | Document5    | NULL                | NULL        | NULL     |

  After applying the `WHERE` clause and selecting the listed attributes, the result will be:

   | name         | id |
   |--------------|----|
   | Document1    | 1  |
   | Document2    | 3  | 

b) 내부 JOIN조항

  SELECT documents.name, downloads.id
  FROM documents
    LEFT OUTER JOIN downloads
      ON documents.id = downloads.document_id
        AND username = 'sandeep'

For above query the intermediate join table will look like this.

    | id(from documents) | name         | id (from downloads) | document_id | username |
    |--------------------|--------------|---------------------|-------------|----------|
    | 1                  | Document1    | 1                   | 1           | sandeep  |
    | 2                  | Document2    | 3                   | 2           | sandeep  |
    | 3                  | Document3    | NULL                | NULL        | NULL     |
    | 4                  | Document4    | NULL                | NULL        | NULL     |
    | 5                  | Document5    | NULL                | NULL        | NULL     |

Notice how the rows in `documents` that did not match both the conditions are populated with `NULL` values.

After Selecting the listed attributes, the result will be:

   | name       | id   |
   |------------|------|
   |  Document1 | 1    |
   |  Document2 | 3    |
   |  Document3 | NULL |
   |  Document4 | NULL |
   |  Document5 | NULL | 


답변

의 위에 INNER JOIN 의 그들은 상호 교환하고, 최적화는 의지에서 다시 정렬됩니다.

의 위에 OUTER JOIN , 그들은 결합의 어느 쪽이 의존하는지에 따라 반드시 상호 교환 가능하지는 않습니다.

가독성에 따라 어느 곳에 나 두었습니다.


답변

내가하는 방법은 다음과 같습니다.

  • ON수행하는 경우 항상 조인 조건을 절 에 넣으십시오 INNER JOIN. 따라서 ON 절에 WHERE 조건을 추가하지 말고 절에 넣으십시오 WHERE.

  • 를 수행하는 LEFT JOIN경우 WHERE 조건을 조인 오른쪽ON 에있는 테이블 의 절에 추가하십시오 . 조인의 오른쪽을 참조하는 WHERE 절을 추가하면 조인이 INNER JOIN으로 변환되므로 필수입니다.

    특정 테이블에없는 레코드를 찾는 경우는 예외입니다. RIGHT JOIN 테이블의 고유 식별자 (NULL이 아닌)에 대한 참조를 WHERE 절에 다음과 같이 추가 WHERE t2.idfield IS NULL합니다. 따라서 조인 오른쪽에있는 테이블을 참조해야하는 유일한 시간은 테이블에없는 레코드를 찾는 것입니다.


답변

내부 조인에서 그들은 같은 것을 의미합니다. 그러나 WHERE vs ON 절에 조인 조건을 넣었는지에 따라 외부 조인에서 다른 결과를 얻을 수 있습니다. 한 번 봐 가지고 이 관련 질문이 답변 (내게로)을.

쿼리를 읽는 사람에게 더 명확하게 보이기 때문에 항상 조인 조건을 ON 절에 넣는 습관이 가장 좋습니다 (외부 조인이고 실제로 where 절에서 원치 않는 한) 테이블이 조인되는 조건 및 WHERE 절이 수십 줄의 길이를 갖는 것을 방지합니다.


답변

이것은 매우 일반적인 질문이므로이 답변은 내가 작성한 이 기사를 기반으로 합니다 .

테이블 관계

우리는 다음 postpost_comment테이블을 고려하십시오 .

<code> post </ code> 및 <code> post_comment </ code> 테이블

post다음과 같은 기록이있다 :

| id | title     |
|----|-----------|
| 1  | Java      |
| 2  | Hibernate |
| 3  | JPA       |

그리고 post_comment다음 세 행이 있습니다.

| id | review    | post_id |
|----|-----------|---------|
| 1  | Good      | 1       |
| 2  | Excellent | 1       |
| 3  | Awesome   | 2       |

SQL 내부 가입

SQL JOIN 절을 사용하면 다른 테이블에 속하는 행을 연관시킬 수 있습니다. 예를 들어, CROSS JOIN 은 두 조인 테이블 사이에 가능한 모든 행 조합을 포함하는 카티 전 곱을 생성합니다.

CROSS JOIN은 특정 시나리오에서 유용하지만 대부분 특정 조건에 따라 테이블을 조인하려고합니다. 그리고 바로 INNER JOIN이 시작됩니다.

SQL INNER JOIN을 사용하면 ON 절을 통해 지정된 조건에 따라 두 테이블을 조인 한 데카르트 곱을 필터링 할 수 있습니다.

SQL INNER JOIN-ON “항상 참”조건

“항상 참”조건을 제공하면 INNER JOIN은 결합 된 레코드를 필터링하지 않으며 결과 세트에는 두 개의 결합 테이블의 카티 전 곱이 포함됩니다.

예를 들어 다음과 같은 SQL INNER JOIN 쿼리를 실행하면

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 1

우리는 모든 조합 postpost_comment기록을 얻을 것입니다 :

| p.id    | pc.id      |
|---------|------------|
| 1       | 1          |
| 1       | 2          |
| 1       | 3          |
| 2       | 1          |
| 2       | 2          |
| 2       | 3          |
| 3       | 1          |
| 3       | 2          |
| 3       | 3          |

따라서 ON 절 조건이 “항상 true”인 경우 INNER JOIN은 CROSS JOIN 쿼리와 동일합니다.

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 1
ORDER BY p.id, pc.id

SQL INNER JOIN-ON “항상 거짓”조건

반면 ON 절 조건이 “always false”이면 결합 된 모든 레코드가 필터링되고 결과 집합이 비어있게됩니다.

따라서 다음 SQL INNER JOIN 쿼리를 실행하면

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 0
ORDER BY p.id, pc.id

결과가 다시 나타나지 않습니다.

| p.id    | pc.id      |
|---------|------------|

위의 쿼리는 다음 CROSS JOIN 쿼리와 동일하기 때문입니다.

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 0
ORDER BY p.id, pc.id

외래 키 및 기본 키 열을 사용하는 SQL INNER JOIN-ON 절

가장 일반적인 ON 절 조건은 다음 쿼리와 같이 자식 테이블의 외래 키 열과 부모 테이블의 기본 키 열을 일치시키는 조건입니다.

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id
ORDER BY p.id, pc.id

위의 SQL INNER JOIN 쿼리를 실행하면 다음과 같은 결과 집합이 나타납니다.

| p.id    | pc.post_id | pc.id      | p.title    | pc.review |
|---------|------------|------------|------------|-----------|
| 1       | 1          | 1          | Java       | Good      |
| 1       | 1          | 2          | Java       | Excellent |
| 2       | 2          | 3          | Hibernate  | Awesome   |

따라서 ON 절 조건과 일치하는 레코드 만 쿼리 결과 집합에 포함됩니다. 이 경우 결과 집합에는 모든 레코드 postpost_comment레코드가 포함됩니다. post아무 관련 한 행은 post_comment그들이 ON 절 조건을 충족 할 수 없기 때문에 제외됩니다.

위의 SQL INNER JOIN 쿼리는 다음 CROSS JOIN 쿼리와 동일합니다.

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p, post_comment pc
WHERE pc.post_id = p.id

타격되지 않은 행은 WHERE 절을 만족시키는 행이며 이러한 레코드 만 결과 집합에 포함됩니다. INNER JOIN 절의 작동 방식을 시각화하는 가장 좋은 방법입니다.

| p.id | pc.post_id | pc.id | p.title | pc.review |
| ------ | ------------ | ------- | ----------- | ----------- -|
| 1 | 1 | 1 | 자바 | 좋은 |
| 1 | 1 | 2 | 자바 | 우수 |
| 1 | 2 | 3 | 자바 | 대박 | 
| 2 | 1 | 1 | 최대 절전 모드 | 좋은 | 
| 2 | 1 | 2 | 최대 절전 모드 | 우수 |
| 2 | 2 | 3 | 최대 절전 모드 | 대박 |
| 3 | 1 | 1 | JPA | 좋은 | 
| 3 | 1 | 2 | JPA | 우수 | 
| 3 | 2 | 3 | JPA | 대박 |

결론

INNER JOIN 문은 INNER JOIN 조회의 ON 절에서 사용한 것과 동일한 조건과 일치하는 WHERE 절을 사용하여 CROSS JOIN으로 다시 작성할 수 있습니다.

이것은 외부 조인이 아닌 내부 조인에만 적용되는 것은 아닙니다.


답변

왼쪽 조인의 경우 where 절on 절 사이 에는 큰 차이가 있습니다 .

예를 들면 다음과 같습니다.

mysql> desc t1;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| fid   | int(11)     | NO   |     | NULL    |       |
| v     | varchar(20) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

fid는 테이블 t2의 id입니다.

mysql> desc t2;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| v     | varchar(10) | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

“구문”에 대한 쿼리 :

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id AND t1.v = 'K'
    -> ;
+----+-----+---+------+------+
| id | fid | v | id   | v    |
+----+-----+---+------+------+
|  1 |   1 | H | NULL | NULL |
|  2 |   1 | B | NULL | NULL |
|  3 |   2 | H | NULL | NULL |
|  4 |   7 | K | NULL | NULL |
|  5 |   5 | L | NULL | NULL |
+----+-----+---+------+------+
5 rows in set (0.00 sec)

“where 절”에 대한 쿼리 :

mysql> SELECT * FROM `t1` left join t2 on fid = t2.id where t1.v = 'K';
+----+-----+---+------+------+
| id | fid | v | id   | v    |
+----+-----+---+------+------+
|  4 |   7 | K | NULL | NULL |
+----+-----+---+------+------+
1 row in set (0.00 sec)

첫 번째 쿼리는 t1.v = ‘K’행에 대해 t1의 레코드와 t2의 종속 행 (있는 경우)을 반환합니다.

두 번째 쿼리는 t1에서 행을 반환하지만 t1.v = ‘K’에 대해서만 행과 관련이 있습니다.