조인에 null 값을 사용할 수없는 이유는 무엇입니까?


13

... row_number() over (partition by... 을 사용하여 쿼리 문제를 해결했습니다 . 이것은 왜 우리가 조인에서 null 값을 가진 열을 사용할 수 없는지에 대한 더 일반적인 질문입니다. 왜 조인을 위해 널이 널과 같을 수 없습니까?

답변:


31

왜 조인을 위해 널이 널과 같을 수 없습니까?

오라클에게 다음과 같이 지시하십시오.

select *
from one t1 
  join two t2 on coalesce(t1.id, -1) = coalesce(t2.id, -1);

(표준 SQL t1.id is not distinct from t2.id에서는 널 안전 항등 연산자를 얻는 데 사용할 수 있지만 Oracle은이를 지원하지 않습니다.)

그러나 이것은 대체 값 (위의 예에서 -1)이 실제로 표에 나타나지 않는 경우에만 작동합니다. 숫자와 같은 "마법"값을 찾는 것은 수도 가능하지만, 문자 값에 매우 어려울 것이다 (특히 때문에 오라클 취급 빈 문자열 null뿐만 아니라)

또한 : id열의 인덱스 가 사용 되지 않습니다 ( 하지만 표현식을 사용하여 함수 기반 인덱스를 정의 할 수 있음coalesce() ).

마법 값없이 모든 유형에 적용되는 다른 옵션 :

              on t1.id = t2.id or (t1.id is null and t2.id is null)

그러나 실제 문제는 이것이 의미가 있습니까?

다음 샘플 데이터를 고려하십시오.

표 하나

id
----
1
2
(null)
(null)

표 2

id
----
1
2
(null)
(null)
(null)

조인에서 어떤 null 값 조합을 선택해야합니까? 위의 예제는 모든 null 값에 대한 크로스 조인과 같은 결과를 낳습니다.

T1_ID  | T2_ID 
-------+-------
     1 |      1
     2 |      2
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)

6

또는 INTERSECT등식 연산자로 두 개의 null을 서로 일치시킬 수 있습니다 .

SELECT
  *
FROM
  t1
  INNER JOIN t2
    ON EXISTS (SELECT t1.ID FROM DUAL INTERSECT SELECT t2.ID FROM DUAL)
;

그림은 이 DBFiddle 데모 를 참조하십시오 .

물론 이것은 실제로는 더 길지 않지만 상당히 입으로 보입니다. BriteSponge의 제안 . 그러나, 말장난을 용서한다면, 앞서 언급 한 표준의 간결함에 대해서는 표준 방식 ( IS NOT DISTINCT FROM오퍼레이터에서는 아직 지원되지 않음)으로 명확하게 일치하지 않습니다.


2

완전성을 위해 함수가 SYS_OP_MAP_NONNULL 을 기하기 위해 12c 문서에 문서화되어 있으므로 null 값을 비교하는 데 를 안전하게 사용할 수 . 이것은 오라클이 무작위로 코드를 제거하지 않고 코드를 손상시키지 않는다는 것을 의미합니다.

SELECT *
FROM   one t1 
       JOIN two t2
         ON SYS_OP_MAP_NONNULL(t1.id) = SYS_OP_MAP_NONNULL(t2.id)

장점은 '매직'숫자 문제를 겪지 않는다는 것입니다.

Oracle 문서의 참조는 기본 구체화 된 뷰 – 구체화 된 뷰에 대한 인덱스 선택에 있습니다.


이제 문서화 되었습니까? AskTom (2003 년) 은 다음과 같이 설명 하기 때문에 : " -문서화되어 있지 않기 때문에 사람들이"읽지 않기 "만하면 다음 릴리스에서 실제로 화를 낼 정도로 충분히 기능사라지거나 기능변경 될 위험 이 있습니다. 유일한 올바른 방법은 다음과 같습니다. where (a = b or (a is null and b is null)) 기간. 그것이 저의 생각입니다. 나는 sys_op_map_nonnull커튼 뒤에있는 사람을 무시하고 사용 하는 것을 고려하지 않을 것 입니다. "
ypercubeᵀᴹ

링크가 있으면 질문에 추가하십시오. 12c 함수 에서 언급을 찾지 못했지만 Oracle 설명서 및 특정 버전을 검색하는 것은 다소 어렵습니다.
ypercubeᵀᴹ

2

디코드를 사용하여 널값을 결합 할 수 있습니다.

on decode(t1.id, t2.id, 1, 0) = 1

decodenull을 동일하게 취급하므로 "마법의"숫자없이 작동합니다. 두 열의 데이터 형식이 같아야합니다.

가장 읽기 쉬운 코드를 만들지는 않지만 여전히 t1.id = t2.id or (t1.id is null and t2.id is null)


1

왜 조인에 null 값을 사용할 수 없습니까? Oracle에서는 다음 두 가지 모두 사실로 평가되지 않습니다.

  • NULL = NULL
  • NULL <> NULL

우리가 이유 IS NULL/ IS NOT NULL널 (null) 값을 확인 할 수 있습니다.
이를 테스트하려면 다음을 수행하십시오.

SELECT * FROM table_name WHERE NULL = NULL

조인은 부울 조건을 평가하고 있으며 다르게 작동하도록 프로그래밍하지 않았습니다. 결합 조건에보다 큰 부호를 넣고 다른 조건을 추가 할 수 있습니다. 그것은 단지 그것을 불리언 표현식으로 평가합니다.

일관성을 위해 조인에서 null은 null과 같을 수 없습니다. 비교 연산자의 일반적인 동작을 무시합니다.


NULL = anything결과 NULLSQL 표준 그렇게 말한다 때문이다. 표현식이 true 인 경우에만 행이 결합 조건을 충족시킵니다.
Laurenz Albe

1
리터럴 구현 세부 사항 (항상 그런 것은 아님) : 일부 DB에는 일부 / 모든 목적으로 NULL을 NULL과 동일하게하는 옵션이 있습니다) 논리적 인 이유가 있습니다. NULL을 알 수 없습니다. NULL과 NULL을 비교할 때, "알 수없는이 것과 다른 알 수없는 것과 동일합니까?"라는 유일한 대답은 "알 수 없음"-다른 NULL (비교 상황에서는 false로 매핑 됨)입니다.
David Spillett

-4

대부분의 관계형 데이터베이스에서 널값은 알 수없는 것으로 간주됩니다. 모든 HEX 0과 혼동해서는 안됩니다. 무언가에 null (알 수 없음)이 포함되어 있으면 비교할 수 없습니다.

Unknown = Known False
Unknown = Unknown False
Unknown >= Known False
Known >= Unknown False

즉, 부울 식에서 피연산자로 null이 있으면 else 부분은 항상 참입니다.

개발자에 의한 null에 대한 일반적인 증오와 달리 null은 그 자리에 있습니다. 알 수없는 경우 null을 사용하십시오.


6
실제로 당신이 가진 모든 예제 비교, yield UNKNOWNFALSE
;,

당신이 옳습니다. 그러나 부울 식의 목적은 참 또는 거짓만을 초래하는 것이므로 여기서 미치게하지 마십시오. :).
jujiro
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.