SQL JOIN-WHERE 절과 ON 절


689

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


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

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


2
미래의 독자와 정보를 위해 SQL 실행 순서를 읽어야합니다. 이는 근본적인 차이점을보다 정확하게 이해하는 데 도움이됩니다.
Rahul Neekhra

답변:


870

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

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

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절이 사실상 동일합니다. 그러나 기능적으로 동일하기 때문에 동일한 결과를 생성한다고해서 두 종류의 절이 동일한 의미 적 의미를 갖는 것은 아닙니다.


83
내부 조인에 대해 "on"절에 where 절을 넣어서 더 나은 성능을 얻을 수 있습니까?
FistOfFury

96
@FistOfFury Sql Server는 쿼리 최적화 프로그램 프로 시저를 사용하여 코드를 컴파일하고 평가하여 최상의 실행 계획을 생성합니다. 완벽하지는 않지만 대부분 중요하지 않으며 동일한 실행 계획을 얻을 수 있습니다.
Joel Coehoorn

18
Postgres에서 나는 그것들이 동등하지 않으며 다른 쿼리 계획을 초래했다고 언급했습니다. ON을 사용하면 materialize가 사용됩니다. WHERE를 사용한 경우 해시를 사용했습니다. 구체화는 해시보다 10 배 더 비용이 많이 드는 나쁜 경우가있었습니다. 단일 ID가 아닌 일련의 ID를 사용하고있었습니다.
JamesHutchison

13
@JamesHutchison 이와 같은 관찰 된 동작을 기반으로 안정적인 성능 일반화를 수행하기는 어렵습니다. 언젠가 사실이었던 것은 다음에 잘못되는 경향이 있습니다. 문서화 된 동작이 아닌 구현 세부 사항이기 때문입니다. 데이터베이스 팀은 항상 최적화 프로그램 성능을 향상시킬 장소를 찾고 있습니다. ON 동작이 WHERE와 일치하도록 개선되지 않으면 놀랄 것입니다. "일반적인 성능 향상"이외의 버전에서 버전에 이르기까지 릴리스 정보의 어느 곳에도 나타나지 않을 수도 있습니다.
Joel Coehoorn

4
@FiHoran 그것은 SQL Server가 작동하는 방식이 아닙니다. 통계에 도움이 될 때 WHERE 절의 항목을 기반으로 적극적으로 사전 필터링합니다.
Joel Coehoorn

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

    ㅏ. 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 | 

40
IMO는 가장 인기있는 답변입니다. 다른 인기있는 답변의 '무엇보다'무슨 일이 벌어지고 있는지 명확하게 보여주기 때문입니다.
psrpsrpsr

1
훌륭한 설명 .... 잘 했어! -그냥 어떻게했는지 궁금 intermediate join table하신가요? '설명'명령이 있습니까?
Manuel Jordan

1
@ManuelJordan 아니오, 이것은 단지 설명을위한 것입니다. 데이터베이스는 중간 테이블을 생성하는 것보다 성능이 뛰어난 작업을 수행 할 수 있습니다.
Sandeep Jindal

나는 아마도 세 번째 도구가 사용되었다고 생각했다.
Manuel Jordan

145

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

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

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



아마도 Where 절, 특히 Linq-To-Entities 람다 식에서 훨씬 더 명확 할 것입니다.Orders.Join( OrderLines, x => x.ID, x => OrderID, (o,l) => new {Orders = o, Lines = l}).Where( ol => ol.Orders.ID = 12345)
Triynko

49

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

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

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

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


8
이것이 내가 지금까지 읽은 최고의 답변입니다. 두뇌가 왼쪽 조인이 왼쪽 테이블의 모든 행 반환 한다는 것을 이해 하면 나중에 의미가 있습니다. 나중에 필터링해야합니다.
Nick Larsen

널 입력 가능 컬럼이있는 테이블을 외부 결합하는 경우, 내부 결합을 작성하지 않고 해당 컬럼이 널인 곳을 "어디에"배치 할 수 있습니까? 특정 테이블에만없는 레코드를 정확하게 찾지는 않습니다. 찾을 수 없음 1. 존재하지 않음 2. 전혀 가치가 없습니다.
근처

"1. 존재하지 않습니다. 2. 전혀 가치가 없습니다"라는 두 가지를 모두 찾을 수 있습니다. 그리고 이것은 해당 필드가 idfield가 아닌 경우에 적용됩니다.
근처

이 사례가 발생했을 때 : 비상 연락없이 신입생 (데이터가 아직 입력되지 않은)을 포함한 참가자를 찾고 있습니다.
근처

30

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

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


26

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

테이블 관계

우리는 다음 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으로 다시 작성할 수 있습니다.

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


11

왼쪽 조인의 경우 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'에 대해서만 행과 관련이 있습니다.


9

옵티 마이저와 관련하여 ON 또는 WHERE로 조인 절을 정의하는지 여부는 차이가 없습니다.

그러나 IMHO, 조인을 수행 할 때 ON 절을 사용하는 것이 훨씬 명확하다고 생각합니다. 이렇게하면 조인의 처리 방법과 나머지 WHERE 절의 혼합 방법을 나타내는 쿼리의 특정 섹션이 있습니다.


7

그 테이블을 고려해 봅시다.

id | SomeData

id | id_A | SomeOtherData

id_A 테이블의 외래 키 A

이 쿼리를 작성 :

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A;

이 결과를 제공합니다 :

/ : part of the result
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+-------+-------------------------+
|/////////////////////////////|
+-----------------------------+

A에 있지만 B에없는 것은 B에 대해 널값이 있음을 의미합니다.


이제의 특정 부분을 고려 B.id_A하여 이전 결과에서 강조하겠습니다.

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|///////|                         |
|/////////////////////|///////|                         |
|/////////////////////+---+///|                         |
|/////////////////////|***|///|                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

이 쿼리를 작성 :

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
AND B.id_A = SpecificPart;

이 결과를 제공합니다 :

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|/////////////////////|       |                         |
|/////////////////////|       |                         |
|/////////////////////+---+   |                         |
|/////////////////////|***|   |                         |
|/////////////////////+---+---+-------------------------+
|/////////////////////////////|
+-----------------------------+

이것은 내부 조인에서 존재하지 않는 값을 제거하기 때문에 B.id_A = SpecificPart


이제 쿼리를 다음과 같이 변경하십시오.

SELECT *
FROM A
LEFT JOIN B
ON A.id = B.id_A
WHERE B.id_A = SpecificPart;

결과는 다음과 같습니다.

/ : part of the result
* : part of the result with the specific B.id_A
                                       B
                      +---------------------------------+
            A         |                                 |
+---------------------+-------+                         |
|                     |       |                         |
|                     |       |                         |
|                     +---+   |                         |
|                     |***|   |                         |
|                     +---+---+-------------------------+
|                             |
+-----------------------------+

전체 결과에 대해 필터링되므로 B.id_A = SpecificPart부품 제거 B.id_A = NULL에, B로되지 않는을


4

데이터를 조인하거나 데이터를 필터링하려고합니까?

가독성을 위해 이러한 사용 사례를 각각 ON 및 WHERE로 분리하는 것이 가장 합리적입니다.

  • ON으로 데이터 조인
  • WHERE에서 데이터 필터링

WHERE 절에 JOIN 조건과 필터링 조건이있는 쿼리를 읽기가 매우 어려워 질 수 있습니다.

성능면에서는 차이가 없어야하지만, SQL 유형에 따라 쿼리 계획이 다르게 처리되기 때문에 시도해 볼 가치가 있습니다. ¯\_(ツ)_/¯ (쿼리 속도에 영향을 미치는 캐싱에주의)

또한 다른 사람들이 지적했듯이 외부 조인을 사용하면 필터 조건이 테이블 중 하나에 만 영향을 미치므로 ON 절에 필터 조건을 배치하면 다른 결과를 얻을 수 있습니다.

https://dataschool.com/learn/difference-between-where-and-on-in-sql에 대한 자세한 게시물을 작성했습니다.


2

SQL에서 'WHERE'및 'ON'절은 일종의 조건부 상태 정책이지만, 'Where'절은 조건을 지정하기 위해 Select / Update 문에서 사용되지만 'ON'절은 'Where'절을 사용합니다. 은 조인에서 사용되며, 테이블을 조인하기 전에 대상 및 소스 테이블에서 레코드가 일치하는지 확인하거나 확인합니다.

예를 들면 :- 'WHERE'

SELECT * FROM employee WHERE employee_id=101

예를 들면 다음과 같습니다.- 'ON'

employee 및 employee_details 테이블이 두 개 있으며 일치하는 열은 employee_id입니다.

SELECT * FROM employee 
INNER JOIN employee_details 
ON employee.employee_id = employee_details.employee_id

나는 당신의 질문에 대답하기를 바랍니다. 설명이 있으면 되돌립니다.


그러나 WHERE대신 키워드 를 사용할 ON수 있습니까? sqlfiddle.com/#!2/ae5b0/14/0
Qwerty

1

그것이 결합 시퀀스 효과라고 생각합니다. 왼쪽 상단 조인의 경우 SQL은 먼저 왼쪽 조인을 수행 한 다음 위치 필터를 수행합니다. 다우 너의 경우 먼저 Orders.ID = 12345를 찾은 다음 가입하십시오.


1

위한 내부는 가입 WHEREON상호 교환 적으로 사용될 수있다. 실제로 ON는 상관 된 하위 쿼리에서 사용할 수 있습니다 . 예를 들면 다음과 같습니다.

update mytable
set myscore=100
where exists (
select 1 from table1
inner join table2
on (table2.key = mytable.key)
inner join table3
on (table3.key = table2.key and table3.key = table1.key)
...
)

이것은 (IMHO) 인간에게 완전히 혼란스럽고, table1( "driver"테이블에 "on"절이 없기 때문에) 무엇이든 연결 하는 것을 잊어 버리는 것은 매우 쉬운 일이지만 합법적입니다.


1

더 나은 성능 테이블을 위해서는 JOINS에 사용할 특수 인덱스 컬럼이 있어야합니다.

따라서 조건이있는 열이 색인 된 열 중 하나가 아닌 경우 WHERE에 유지하는 것이 좋습니다.

따라서 인덱싱 된 열을 사용하여 JOIN 한 다음 JOIN 후에 인덱스가없는 열에서 조건을 실행합니다.


1

일반적으로 두 테이블이 이미 조인되면 WHERE 절에서 필터링이 처리됩니다. 조인하기 전에 테이블 중 하나 또는 둘 다를 필터링 할 수 있습니다. 즉, where 절은 전체 결과 집합에 적용되고 on 절은 해당 조인에만 적용됩니다.


DBMS가 "정상적으로"최적화되기 때문에 그렇지 않습니다.
philipxy

1

이 차이점은 SQL논리적 연산 순서를 통해 가장 잘 설명 될 수 있다고 생각합니다 .

  • FROM (조인 포함)
  • WHERE
  • GROUP BY
  • 집계
  • HAVING
  • WINDOW
  • SELECT
  • DISTINCT
  • UNION, INTERSECT,EXCEPT
  • ORDER BY
  • OFFSET
  • FETCH

조인은 select 문의 절이 아니라 내부의 연산자입니다 FROM. 따라서 ON해당 JOIN연산자에 속하는 모든 절 은 논리적 처리가 절에 도달 할 때 논리적 으로 "이미 발생했습니다" WHERE. 이것은LEFT JOIN 예를 들어, 외부 조인의 의미론이 이미WHERE 조항이 적용될 .

이 블로그 게시물에서 다음 예제를 더 자세히 설명했습니다 . 이 쿼리를 실행할 때 :

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
WHERE film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

LEFT JOIN배우가 영화에서 재생되지 않은 경우에도 배우가 필터링되기 때문에 그것으로 정말, 유용한 효과가없는 FILM_IDNULL하고 WHERE절은 이러한 행을 필터링합니다. 결과는 다음과 같습니다.

ACTOR_ID  FIRST_NAME  LAST_NAME  COUNT
--------------------------------------
194       MERYL       ALLEN      1
198       MARY        KEITEL     1
30        SANDRA      PECK       1
85        MINNIE      ZELLWEGER  1
123       JULIANNE    DENCH      1

즉 우리가 마치 두 테이블에 합류 한 것처럼. ON절 에서 필터 술어를 이동하면 이제 외부 결합의 기준이됩니다.

SELECT a.actor_id, a.first_name, a.last_name, count(fa.film_id)
FROM actor a
LEFT JOIN film_actor fa ON a.actor_id = fa.actor_id
  AND film_id < 10
GROUP BY a.actor_id, a.first_name, a.last_name
ORDER BY count(fa.film_id) ASC;

결과에는 영화가 없거나 영화가없는 배우가 포함됩니다. FILM_ID < 10

ACTOR_ID  FIRST_NAME  LAST_NAME     COUNT
-----------------------------------------
3         ED          CHASE         0
4         JENNIFER    DAVIS         0
5         JOHNNY      LOLLOBRIGIDA  0
6         BETTE       NICHOLSON     0
...
1         PENELOPE    GUINESS       1
200       THORA       TEMPLE        1
2         NICK        WAHLBERG      1
198       MARY        KEITEL        1

한마디로

논리적으로 가장 적합한 곳에 술어를 배치하십시오.


0

당신의 질문에 관해서는

서버가 얻을 수있는 한 내부 조인의 'on'또는 'where'둘 다 동일합니다.

select * from a inner join b on a.c = b.c

select * from a inner join b where a.c = b.c

모든 통역사가 아는 'where'옵션은 피해야 할 수도 있습니다. 물론 'on'절이 더 명확합니다.


-5

이것이 나의 해결책이다.

SELECT song_ID,songs.fullname, singers.fullname
FROM music JOIN songs ON songs.ID = music.song_ID  
JOIN singers ON singers.ID = music.singer_ID
GROUP BY songs.fullname

당신 은 있어야 합니다GROUP BY 작업에 그것을 얻을 수 있습니다.

이 도움을 바랍니다.


10
song_id 및 singers.fullname도 선택하는 동안 songs.fullname 만 그룹화하면 대부분의 데이터베이스에서 문제가됩니다.
btilly
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.