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
답변
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
.
답변
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)
답변
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 비교 연산자 를 사용하십시오 .<=>
=
답변
명확성을 위해 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