읽은 후에 는 명시 적 vs 암시 적 SQL 조인 의 복제본 이 아닙니다 . 대답은 관련이있을 수도 있고 같은 내용 일 수도 있지만 질문 은 다릅니다.
차이점은 무엇이며 각각 어떻게해야합니까?
이론을 올바르게 이해하면 쿼리 최적화 프로그램에서 두 가지를 모두 사용할 수 있어야합니다.
읽은 후에 는 명시 적 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 |
intermediate join table
하신가요? '설명'명령이 있습니까?
의 위에 INNER JOIN
의 그들은 상호 교환하고, 최적화는 의지에서 다시 정렬됩니다.
의 위에 OUTER JOIN
, 그들은 결합의 어느 쪽이 의존하는지에 따라 반드시 상호 교환 가능하지는 않습니다.
가독성에 따라 어느 곳에 나 두었습니다.
Orders.Join( OrderLines, x => x.ID, x => OrderID, (o,l) => new {Orders = o, Lines = l}).Where( ol => ol.Orders.ID = 12345)
내가하는 방법은 다음과 같습니다.
를 ON
수행하는 경우 항상 조인 조건을 절 에 넣으십시오 INNER JOIN
. 따라서 ON 절에 WHERE 조건을 추가하지 말고 절에 넣으십시오 WHERE
.
를 수행하는 LEFT JOIN
경우 WHERE 조건을 조인 오른쪽ON
에있는 테이블 의 절에 추가하십시오 . 조인의 오른쪽을 참조하는 WHERE 절을 추가하면 조인이 INNER JOIN으로 변환되므로 필수입니다.
특정 테이블에없는 레코드를 찾는 경우는 예외입니다. RIGHT JOIN 테이블의 고유 식별자 (NULL이 아닌)에 대한 참조를 WHERE 절에 다음과 같이 추가 WHERE t2.idfield IS NULL
합니다. 따라서 조인 오른쪽에있는 테이블을 참조해야하는 유일한 시간은 테이블에없는 레코드를 찾는 것입니다.
우리는 다음 post
과 post_comment
테이블을 고려하십시오 .
는 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 JOIN 절을 사용하면 다른 테이블에 속하는 행을 연관시킬 수 있습니다. 예를 들어, CROSS JOIN 은 두 조인 테이블 사이에 가능한 모든 행 조합을 포함하는 카티 전 곱을 생성합니다.
CROSS JOIN은 특정 시나리오에서 유용하지만 대부분 특정 조건에 따라 테이블을 조인하려고합니다. 그리고 바로 INNER JOIN이 시작됩니다.
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
우리는 모든 조합 post
과 post_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
반면 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
가장 일반적인 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 절 조건과 일치하는 레코드 만 쿼리 결과 집합에 포함됩니다. 이 경우 결과 집합에는 모든 레코드 post
와 post_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'에 대해서만 행과 관련이 있습니다.
그 테이블을 고려해 봅시다.
ㅏ
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로되지 않는을
데이터를 조인하거나 데이터를 필터링하려고합니까?
가독성을 위해 이러한 사용 사례를 각각 ON 및 WHERE로 분리하는 것이 가장 합리적입니다.
WHERE 절에 JOIN 조건과 필터링 조건이있는 쿼리를 읽기가 매우 어려워 질 수 있습니다.
성능면에서는 차이가 없어야하지만, SQL 유형에 따라 쿼리 계획이 다르게 처리되기 때문에 시도해 볼 가치가 있습니다. ¯\_(ツ)_/¯
(쿼리 속도에 영향을 미치는 캐싱에주의)
또한 다른 사람들이 지적했듯이 외부 조인을 사용하면 필터 조건이 테이블 중 하나에 만 영향을 미치므로 ON 절에 필터 조건을 배치하면 다른 결과를 얻을 수 있습니다.
https://dataschool.com/learn/difference-between-where-and-on-in-sql에 대한 자세한 게시물을 작성했습니다.
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
상호 교환 적으로 사용될 수있다. 실제로 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"절이 없기 때문에) 무엇이든 연결 하는 것을 잊어 버리는 것은 매우 쉬운 일이지만 합법적입니다.
이 차이점은 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_ID
것 NULL
하고 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
논리적으로 가장 적합한 곳에 술어를 배치하십시오.
이것이 나의 해결책이다.
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
작업에 그것을 얻을 수 있습니다.
이 도움을 바랍니다.