MySQL에서 완전 외부 조인을하고 싶습니다. 이것이 가능한가? MySQL은 Full Outer Join을 지원합니까?
MySQL에서 완전 외부 조인을하고 싶습니다. 이것이 가능한가? MySQL은 Full Outer Join을 지원합니까?
답변:
MySQL에는 FULL JOIN이 없지만 에뮬레이션 할 수 있습니다 .
이 SO 질문 에서 코드 샘플을 작성 하면 다음이 있습니다.
두 개의 테이블 t1, t2로 :
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
위 쿼리는 FULL OUTER JOIN 연산이 중복 행을 생성하지 않는 특수한 경우에 작동합니다. 위 쿼리는 UNION
set 연산자에 따라 쿼리 패턴에 의해 도입 된 중복 행을 제거합니다. 두 번째 쿼리에 반 조인 패턴을 사용하여 중복 행이 도입되는 것을 피한 다음 UNION ALL 집합 연산자를 사용하여 두 집합을 결합 할 수 있습니다. FULL OUTER JOIN이 중복 행을 리턴하는보다 일반적인 경우에는 다음을 수행 할 수 있습니다.
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.id IS NULL
(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
t1
and에 중복 행이 없으면 t2
이 답변의 쿼리는 FULL OUTER JOIN을 에뮬레이트하는 결과 집합을 반환합니다. 그러나 더 일반적인 경우, 예를 들어 SELECT 목록에 반환 된 행을 고유하게 만들기에 충분한 열 / 표현이 포함되어 있지 않으면이 쿼리 패턴 으로는 에서 생성 된 집합을 재현하기에 충분하지 않습니다FULL OUTER JOIN
. 보다 충실한 에뮬레이션을 얻으려면 UNION ALL
set 연산자가 필요하고 쿼리 중 하나에 안티 조인 패턴 이 필요합니다 . Pavle Lekic (위) 의 주석은 올바른 쿼리 패턴을 제공합니다 .
Pablo Santa Cruz 가 한 대답 은 정확합니다. 그러나 누군가이 페이지를 우연히 발견하고 더 자세한 설명을 원할 경우 여기에 자세한 설명이 있습니다.
다음 테이블이 있다고 가정하십시오.
-- t1
id name
1 Tim
2 Marta
-- t2
id name
1 Tim
3 Katarina
내부 조인은 다음과 같습니다.
SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
다음과 같이 두 테이블에 모두 나타나는 레코드 만 가져 오십시오.
1 Tim 1 Tim
내부 조인은 명시 적으로 양방향이기 때문에 방향이 없습니다 (왼쪽 또는 오른쪽). 양쪽에 일치해야합니다.
반면 외부 조인은 다른 테이블에서 일치하지 않는 레코드를 찾기위한 것입니다. 따라서, 조인의 어느 쪽 이 누락 된 레코드를 가질 수 있는지 지정해야합니다.
LEFT JOIN
과 RIGHT JOIN
에 대한 나타내는 표현이된다 LEFT OUTER JOIN
및 RIGHT OUTER JOIN
; 아래의 전체 이름을 사용하여 외부 조인과 내부 조인의 개념을 강화합니다.
왼쪽 외부 조인은 다음과 같습니다.
SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
... 다음과 같이 오른쪽 테이블에서 일치하는지 여부에 관계없이 왼쪽 테이블에서 모든 레코드를 가져옵니다.
1 Tim 1 Tim
2 Marta NULL NULL
다음과 같은 오른쪽 외부 조인
SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
... 왼쪽 테이블과 일치하는지 여부에 관계없이 오른쪽 테이블에서 모든 레코드를 가져올 수 있습니다.
1 Tim 1 Tim
NULL NULL 3 Katarina
완전 외부 조인은 다른 테이블과 일치하는지 여부에 관계없이 두 테이블의 모든 레코드를 제공하며 일치하지 않는 양쪽에 NULL이 있습니다. 결과는 다음과 같습니다.
1 Tim 1 Tim
2 Marta NULL NULL
NULL NULL 3 Katarina
그러나 Pablo Santa Cruz가 지적했듯이 MySQL은 이것을 지원하지 않습니다. 다음과 같이 왼쪽 조인과 오른쪽 조인의 UNION을 수행하여 에뮬레이션 할 수 있습니다.
SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
UNION
SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;
UNION
"이 두 쿼리를 모두 실행 한 다음 결과를 서로 쌓아 올리십시오"라는 의미로 생각할 수 있습니다 . 일부 행은 첫 번째 쿼리에서 나오고 일부는 두 번째 쿼리에서 나옵니다.
UNION
MySQL에서 a 는 정확한 중복을 제거합니다. Tim은 두 쿼리 모두에 표시되지만 결과 UNION
는 그를 한 번만 나열합니다. 저의 데이터베이스 전문가는이 동작에 의존해서는 안된다고 생각합니다. 따라서 더 명확하게 WHERE
하기 위해 두 번째 쿼리에 절을 추가 할 수 있습니다 .
SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
UNION
SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
WHERE `t1`.`id` IS NULL;
당신이 다른 한편, 만약 싶어 어떤 이유로 중복을보고, 당신은 사용할 수 있습니다 UNION ALL
.
FULL OUTER JOIN
. 그런 식으로 쿼리를 수행하고 UNION을 사용하여 중복을 제거하는 데 아무런 문제가 없습니다. 그러나 실제로를 복제 FULL OUTER JOIN
하려면 안티 조인 쿼리 중 하나가 필요합니다.
UNION
작업이 중복을 제거 한다는 것은 사실입니다 . 그러나 FULL OUTER JOIN에 의해 리턴되는 중복 행을 포함하여 모든 중복 행을 제거합니다. 에뮬레이션하려면 a FULL JOIN b
올바른 패턴이 (a LEFT JOIN b) UNION ALL (b ANTI JOIN a)
있습니다.
union
쿼리를 사용하면 중복이 full outer join
제거되며 중복을 제거하지 않는 동작과 다릅니다 .
[Table: t1] [Table: t2]
value value
------- -------
1 1
2 2
4 2
4 5
이것은 다음의 예상 결과입니다 full outer join
.
value | value
------+-------
1 | 1
2 | 2
2 | 2
Null | 5
4 | Null
4 | Null
이는 사용의 결과 left
와 right Join
와 union
:
value | value
------+-------
Null | 5
1 | 1
2 | 2
4 | Null
내 제안 쿼리는 다음과 같습니다
select
t1.value, t2.value
from t1
left outer join t2
on t1.value = t2.value
union all -- Using `union all` instead of `union`
select
t1.value, t2.value
from t2
left outer join t1
on t1.value = t2.value
where
t1.value IS NULL
예상 결과와 동일한 위 쿼리 결과 :
value | value
------+-------
1 | 1
2 | 2
2 | 2
4 | NULL
4 | NULL
NULL | 5
@Steve Chambers : [의견에서 감사합니다!]
참고 : 이는 효율성과 같은 결과를 생성하는 데 가장 적합한 솔루션 일 수 있습니다FULL OUTER JOIN
. 이 블로그 게시물 은 또한 방법 2에서 인용 한 내용을 잘 설명합니다. "이것은 중복 행을 올바르게 처리하고 행하지 말아야 할 것은 포함하지 않습니다.UNION ALL
평범한 대신 사용해야UNION
하므로 유지하려는 중복을 제거합니다. 중복을 정렬하거나 제거 할 필요가 없으므로 큰 결과 집합에서 훨씬 더 효율적일 수 있습니다. "
full outer join
시각화 및 수학 에서 제공되는 다른 솔루션을 추가하기로 결정 했지만 위의 방법이 아니라 더 읽기 쉽습니다.
완전 외부 조인은
(t1 ∪ t2)
모두 포함t1
또는 포함t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only
: 모두 포함 되지 않은 모두t1
및t2
포함t1
되지 않은t2
모든t2
것을 의미합니다t1
.
-- (t1 ∩ t2): all in both t1 and t2
select t1.value, t2.value
from t1 join t2 on t1.value = t2.value
union all -- And plus
-- all in t1 that not exists in t2
select t1.value, null
from t1
where not exists( select 1 from t2 where t2.value = t1.value)
union all -- and plus
-- all in t2 that not exists in t1
select null, t2.value
from t2
where not exists( select 1 from t1 where t2.value = t1.value)
FULL OUTER JOIN
. 이 블로그 게시물 은 또한 방법 2에서 인용하는 방법을 잘 설명합니다. "이것은 중복 행을 올바르게 처리하고 행하지 말아야 할 것은 포함하지 않습니다. 일반 UNION 대신 UNION ALL을 사용해야합니다. 중복을 정렬하거나 제거 할 필요가 없기 때문에 대규모 결과 집합에서 훨씬 더 효율적일 수 있습니다. "
MySql에는 FULL-OUTER-JOIN 구문이 없습니다. 다음과 같이 LEFT JOIN과 RIGHT JOIN을 모두 수행하여 에뮬레이션해야합니다.
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
그러나 MySql에는 RIGHT JOIN 구문이 없습니다. MySql의 외부 조인 단순화 에 따르면 오른쪽 조인은 쿼리 의 FROM
and ON
절에서 t1과 t2를 전환하여 동등한 왼쪽 조인으로 변환 됩니다. 따라서 MySql Query Optimizer는 원래 쿼리를 다음과 같이 변환합니다.
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
이제 같이 원래 쿼리를 작성에 전혀 해를 끼치 지 당신이있는 WHERE 절과 같은 조건이있는 경우 말하지만, 없다 에 가입하기 전에 - 온 조건 또는 AND 조건 ON
A는 절을, 가입시 - 술어 다음, 당신을 악마를보고 싶을 수도 있습니다. 자세한 내용입니다.
MySql 쿼리 옵티마이 저는 술어가 널 거부 인지 여부를 정기적으로 점검합니다 . 이제 RIGHT JOIN을 수행했지만 t1의 열에 WHERE 술어가 있으면 널 거부 시나리오 가 발생할 위험이 있습니다.
예를 들어, 다음 쿼리는-
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
Query Optimizer가 다음으로 번역됩니다.
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'
따라서 테이블 순서가 변경되었지만 술어는 여전히 t1에 적용되지만 t1은 이제 'ON'절에 있습니다. t1.col1이 NOT NULL
열로 정의되면 이 쿼리는 널이 거부 됩니다.
null 거부 된 모든 외부 조인 (왼쪽, 오른쪽, 전체)은 MySql에 의해 내부 조인으로 변환됩니다.
따라서 예상 한 결과는 MySql이 반환하는 결과와 완전히 다를 수 있습니다. MySql의 RIGHT JOIN에 버그가 있다고 생각할 수도 있지만 그렇지 않습니다. MySql 쿼리 최적화 프로그램이 작동하는 방식입니다. 따라서 담당자는 쿼리를 구성 할 때 이러한 뉘앙스에주의를 기울여야합니다.
SQLite에서는 다음을 수행해야합니다.
SELECT *
FROM leftTable lt
LEFT JOIN rightTable rt ON lt.id = rt.lrid
UNION
SELECT lt.*, rl.* -- To match column set
FROM rightTable rt
LEFT JOIN leftTable lt ON lt.id = rt.lrid
위의 답변 중 어느 것도 중복 된 값이있을 때 의미를 따르지 않기 때문에 실제로 올바른 것은 없습니다.
(이 복제본 에서와 같은) 쿼리의 경우 :
SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;
올바른 내용은 다음과 같습니다.
SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION -- This is intentionally UNION to remove duplicates
SELECT name FROM t2
) n LEFT JOIN
t1
ON t1.name = n.name LEFT JOIN
t2
ON t2.name = n.name;
이 NULL
값 으로 작업해야하는 경우 (필요할 수도 있음) 대신 NULL
-safe 비교 연산자 를 사용하십시오 .<=>
=
FULL OUTER JOIN
때마다 다른 결과를 제공 할 수 있습니다 name
. union all
안티 조인 패턴 이있는 쿼리는 외부 조인 동작을 올바르게 재현해야하지만, 더 적합한 솔루션은 컨텍스트와 테이블에서 활성화 된 제약 조건에 따라 다릅니다.
union all
하지만, 그 대답은 기존 복제본을 유지하지만 새로운 복제본을 추가하지 못하게하는 첫 번째 쿼리 또는 두 번째 쿼리에서 안티 조인 패턴을 누락합니다. 상황에 따라이 솔루션과 같은 다른 솔루션이 더 적합 할 수 있습니다.
명확성을 위해 shA.t의 쿼리를 수정했습니다.
-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value
UNION ALL -- include duplicates
-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t2.value IS NULL
교차 결합 솔루션 에 대해 무엇을 말했 습니까?
SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2
ON 1=1;
select (select count(*) from t1) * (select count(*) from t2))
시켜 결과 집합의 행 과 함께 가능한 모든 조합 세트를 생성합니다 .
SELECT
a.name,
b.title
FROM
author AS a
LEFT JOIN
book AS b
ON a.id = b.author_id
UNION
SELECT
a.name,
b.title
FROM
author AS a
RIGHT JOIN
book AS b
ON a.id = b.author_id
또한 가능하지만 select에서 동일한 필드 이름을 언급해야합니다.
SELECT t1.name, t2.name FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.name, t2.name FROM t2
LEFT JOIN t1 ON t1.id = t2.id
응답을 수정하고 모든 행을 포함합니다 (Pavele Lekic의 응답을 기반으로 함)
(
SELECT a.* FROM tablea a
LEFT JOIN tableb b ON a.`key` = b.key
WHERE b.`key` is null
)
UNION ALL
(
SELECT a.* FROM tablea a
LEFT JOIN tableb b ON a.`key` = b.key
where a.`key` = b.`key`
)
UNION ALL
(
SELECT b.* FROM tablea a
right JOIN tableb b ON b.`key` = a.key
WHERE a.`key` is null
);
tablea
, 일치하지 않는 행만 반환 tableb
하고 그 반대도 마찬가지입니다. 당신이하려고 UNION ALL
,하는 것이 두 테이블이 동등하게 보장되지 않으므로 열을 주문한 경우에만 작동합니다.
대답:
SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;
다음과 같이 다시 만들 수 있습니다.
SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
LEFT JOIN t1 ON t1.id = tmp.id
LEFT JOIN t2 ON t2.id = tmp.id;
UNION 또는 UNION ALL 답변을 사용하면 기본 테이블에 중복 항목이있는 경우에 적용되지 않습니다.
설명:
UNION 또는 UNION ALL이 커버 할 수없는 경우가 있습니다. FULL OUTER JOIN을 지원하지 않으므로 mysql에서 이것을 테스트 할 수 없지만이를 지원하는 데이터베이스에서는이를 설명 할 수 있습니다.
WITH cte_t1 AS
(
SELECT 1 AS id1
UNION ALL SELECT 2
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 6
),
cte_t2 AS
(
SELECT 3 AS id2
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 6
)
SELECT * FROM cte_t1 t1 FULL OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2;
This gives us this answer:
id1 id2
1 NULL
2 NULL
NULL 3
NULL 4
5 5
6 6
6 6
6 6
6 6
UNION 솔루션 :
SELECT * FROM cte_t1 t1 LEFT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
UNION
SELECT * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
잘못된 답변을 제공합니다.
id1 id2
NULL 3
NULL 4
1 NULL
2 NULL
5 5
6 6
UNION ALL 솔루션 :
SELECT * FROM cte_t1 t1 LEFT OUTER join cte_t2 t2 ON t1.id1 = t2.id2
UNION ALL
SELECT * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
또한 올바르지 않습니다.
id1 id2
1 NULL
2 NULL
5 5
6 6
6 6
6 6
6 6
NULL 3
NULL 4
5 5
6 6
6 6
6 6
6 6
이 쿼리는 다음과 같습니다.
SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
LEFT JOIN t1 ON t1.id = tmp.id
LEFT JOIN t2 ON t2.id = tmp.id;
다음을 제공합니다.
id1 id2
1 NULL
2 NULL
NULL 3
NULL 4
5 5
6 6
6 6
6 6
6 6
순서는 다르지만 정답과 일치합니다.
UNION ALL
해결책이 잘못되었습니다 . 또한 UNION
필요한 중복 제거로 인해 큰 소스 테이블에서 속도가 느려지 는 솔루션을 제공합니다 . 마지막으로 필드 id
가 subquery에 없기 때문에 컴파일 되지 않습니다 tmp
.
UNION ALL
해결 방법 : ...도 올바르지 않습니다." 제시 한 코드 where t1.id1 is null
는에서 제공해야하는 오른쪽 조인 ( ) 에서 교차 제외를 제외 합니다 UNION ALL
. 다시 말해, 귀하의 솔루션은 다른 솔루션 중 하나가 잘못 구현 된 경우에만 다른 모든 솔루션보다 우선합니다. "귀여움"에 대한 포인트. 정말 사과했습니다.
표준 SQL 말한다 full join on
입니다 inner join on
행 union all
널 (null) 확장 타의 추종을 불허하는 왼쪽 테이블 행은 union all
우측 테이블 행이 널 (null)로 연장했다. 즉 inner join on
행 union all
을 입력 left join on
하지만 inner join on
union all
행을 입력 right join on
하지는 않습니다 inner join on
.
즉 left join on
행 union all
right join on
이에 없습니다 inner join on
. 당신이 알고있는 경우 또는 inner join on
결과가 "다음 특정 권리 테이블 컬럼에 널 (null)을 가질 수 right join on
없는 행을 inner join on
"의 행입니다 right join on
와 on
연장 조건 and
이 열은 is null
.
즉, 마찬가지로 right join on
union all
적절한 left join on
행입니다.
에서 "내부 조인"과 "외부 조인"의 차이점은 무엇입니까? :
(SQL Standard 2006 SQL / Foundation 7.7 구문 규칙 1, 일반 규칙 1 b, 3 c & d, 5 b)