Tại sao tôi không thể sử dụng giá trị null trong các phép nối?


13

Tôi đã giải quyết vấn đề truy vấn bằng cách sử dụng ... row_number() over (partition by... đây là một câu hỏi tổng quát hơn về lý do tại sao chúng ta không thể sử dụng các cột có giá trị null trong các phép nối. Tại sao null không thể bằng null vì lợi ích của việc tham gia?

Câu trả lời:


31

Tại sao null không thể bằng null vì lợi ích của việc tham gia?

Chỉ cần nói với Oracle để làm điều đó:

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

(Lưu ý rằng trong SQL tiêu chuẩn, bạn có thể sử dụng t1.id is not distinct from t2.idđể có được toán tử đẳng thức an toàn null, nhưng Oracle không hỗ trợ điều đó)

Nhưng điều này sẽ chỉ hoạt động nếu giá trị thay thế (-1 trong ví dụ trên) không thực sự xuất hiện trong bảng. Việc tìm kiếm một giá trị "ma thuật" như vậy cho các số có thể là có thể, nhưng sẽ rất khó cho các giá trị ký tự (đặc biệt là vì Oracle cũng xử lý một chuỗi trống null)

Thêm vào đó: không có chỉ mục nào trên các idcột sẽ được sử dụng (bạn có thể xác định chỉ mục dựa trên hàm với coalesce()biểu thức).

Một tùy chọn khác hoạt động cho tất cả các loại, không có giá trị ma thuật:

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

Nhưng câu hỏi thực sự là: điều này có ý nghĩa?

Xem xét các dữ liệu mẫu sau:

Bảng một

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

Bảng hai

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

Sự kết hợp nào của các giá trị null nên được chọn trong phép nối? Ví dụ trên của tôi sẽ dẫn đến kết quả giống như tham gia chéo cho tất cả các giá trị null.

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

6

Ngoài ra, bạn có thể làm cho hai null khớp với nhau bằng cách sử dụng INTERSECTtoán tử đẳng thức:

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

Xem bản demo DBFiddle này để minh họa.

Tất nhiên, điều này có vẻ khá vừa miệng, mặc dù nó thực sự không dài hơn nhiều so với đề xuất của BriteSponge . Tuy nhiên, nó chắc chắn không phải là một trận đấu, nếu bạn tha thứ cho trò chơi chữ, với sự đồng nhất của cách được đề cập trước đó theo cách tiêu chuẩn nhận xét, đó là IS NOT DISTINCT FROMtoán tử, chưa được hỗ trợ trong Oracle.


2

Để hoàn thiện, tôi sẽ đề cập rằng chức năng SYS_OP_MAP_NONNULLhiện có thể được sử dụng một cách an toàn để so sánh các giá trị là null vì hiện tại nó được ghi lại trong tài liệu 12c. Điều này có nghĩa là Oracle sẽ không xóa ngẫu nhiên và phá mã của bạn.

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

Ưu điểm là bạn không gặp phải vấn đề về số lượng 'ma thuật'.

Tham chiếu trong các tài liệu của Oracle là ở Chế độ xem được vật chất hóa cơ bản - Chọn các chỉ mục cho các khung nhìn được vật chất hóa .


Vì vậy, nó là tài liệu bây giờ? Bởi vì AskTom (năm 2003) đã tuyên bố: " - nó không có giấy tờ, và do đó có nguy cơ biến mất hoặc thay đổi chức năng đủ để nói rằng sẽ khiến mọi người chỉ" ngừng đọc "ở đó và bạn có thể thực sự phát điên trong lần phát hành tiếp theo. cách duy nhất ĐÚNG là: where (a = b or (a is null and b is null)) thời gian. đó là suy nghĩ của tôi về nó. Tôi sẽ không cân nhắc việc sử dụng sys_op_map_nonnull, bỏ qua người đàn ông đằng sau bức màn. "
ypercubeᵀᴹ

Nếu bạn có liên kết, xin vui lòng thêm nó vào câu hỏi. Tôi chưa tìm thấy đề cập đến trong Hàm 12c nhưng việc tìm kiếm tài liệu và phiên bản cụ thể của Oracle khá khó khăn.
ypercubeᵀᴹ

2

Bạn có thể tham gia các giá trị null bằng cách giải mã:

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

decodecoi null là bằng nhau, vì vậy điều này hoạt động mà không có số "ma thuật". Hai cột phải có cùng kiểu dữ liệu.

Nó sẽ không tạo ra mã dễ đọc nhất, nhưng có lẽ vẫn tốt hơn t1.id = t2.id or (t1.id is null and t2.id is null)


1

Tại sao bạn không thể sử dụng giá trị null trong các phép nối? Trong Oracle, cả hai điều sau đây không được đánh giá là đúng:

  • NULL = NULL
  • NULL <> NULL

Đó là lý do tại sao chúng ta phải IS NULL/ IS NOT NULLkiểm tra các giá trị null.
Để kiểm tra điều này, bạn chỉ cần làm:

SELECT * FROM table_name WHERE NULL = NULL

Các tham gia đang đánh giá một điều kiện boolean và họ không lập trình cho họ hoạt động khác đi. Bạn có thể đặt một dấu lớn hơn trong điều kiện nối và thêm các điều kiện khác; nó chỉ đánh giá nó như một biểu thức boolean.

Tôi đoán một null không thể bằng null trong các phép nối vì sự thống nhất. Nó sẽ thách thức hành vi thông thường của toán tử so sánh.


NULL = anythingkết quả là NULLdo tiêu chuẩn SQL nói như vậy. Một hàng thỏa mãn điều kiện nối chỉ khi biểu thức là đúng.
Laurenz Albe

1
Ngoài chi tiết triển khai theo nghĩa đen (không phải lúc nào cũng như vậy: một số DB có tùy chọn đánh đồng NULL với NULL cho một số / tất cả các mục đích) có một lý do hợp lý: NULL không rõ. Khi bạn so sánh NULL với NULL, bạn sẽ hỏi "điều này chưa biết bằng với điều chưa biết khác" mà câu trả lời hợp lý duy nhất là "không xác định" - một NULL khác (được ánh xạ thành sai trong tình huống so sánh).
David Spillett

-4

Một giá trị null trong hầu hết các cơ sở dữ liệu quan hệ được coi là UNKNOWN. Không nên nhầm lẫn với tất cả các số không HEX. nếu một cái gì đó chứa null (không xác định), bạn không thể so sánh nó.

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

Điều đó có nghĩa là, bất cứ khi nào bạn có null là toán hạng trong biểu thức boolean, phần khác sẽ luôn luôn đúng.

Trái ngược với sự căm ghét chung đối với null của các nhà phát triển, null có chỗ đứng của nó. Nếu một cái gì đó không rõ, sử dụng null.


6
Trên thực tế tất cả các ví dụ so sánh bạn có, năng suất UNKNOWN, không FALSE;)
ypercubeᵀᴹ

Bạn đã đúng, tuy nhiên mục đích của biểu thức boolean là chỉ cho kết quả đúng hoặc sai, vì vậy, chúng ta đừng nổi điên ở đây :).
jujiro
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.