Tại sao Oracle 9i coi một chuỗi rỗng là NULL?


216

Tôi biết rằng nó không xem xét '' như NULL, nhưng điều đó không làm được gì nhiều để cho tôi biết tại sao đây là trường hợp. Theo tôi hiểu các thông số kỹ thuật của SQL, '' không giống như NULL- một là dữ liệu hợp lệ và cái còn lại cho thấy sự vắng mặt của thông tin tương tự.

Vui lòng suy đoán, nhưng vui lòng cho biết nếu đó là trường hợp. Nếu có ai từ Oracle có thể bình luận về nó, điều đó thật tuyệt vời!


9
Hãy suy đoán? Bằng cách nào đó tôi không nghĩ rằng nó sẽ cung cấp cho bạn bộ câu trả lời hay nhất ..
SCdF

1
Tôi cho là không, nhưng tôi không chắc có bất kỳ sự chắc chắn nào về chủ đề này, vì vậy tôi nghĩ rằng tôi sẽ mở cửa. Có vẻ như đã làm việc ổn, cho đến nay.
Chris R


Câu trả lời:


216

Tôi tin rằng câu trả lời là Oracle rất, rất cũ.

Quay trở lại thời xa xưa trước khi có một tiêu chuẩn SQL, Oracle đã đưa ra quyết định thiết kế rằng các chuỗi VARCHAR/ VARCHAR2cột trống trong đó NULLvà chỉ có một ý nghĩa về NULL (có những lý thuyết quan hệ sẽ phân biệt giữa dữ liệu chưa bao giờ được nhắc đến, dữ liệu trong đó câu trả lời tồn tại nhưng người dùng không biết, dữ liệu không có câu trả lời, v.v ... tất cả đều tạo thành ý nghĩa nào đó NULL).

Vào thời điểm tiêu chuẩn SQL xuất hiện và đồng ý rằng NULLvà chuỗi rỗng là các thực thể riêng biệt, đã có người dùng Oracle có mã giả định hai mã này là tương đương nhau. Vì vậy, Oracle về cơ bản chỉ còn lại các tùy chọn phá mã hiện có, vi phạm tiêu chuẩn SQL hoặc đưa ra một số loại tham số khởi tạo sẽ thay đổi chức năng của số lượng truy vấn lớn. Vi phạm tiêu chuẩn SQL (IMHO) là ít phá vỡ nhất trong ba tùy chọn này.

Oracle đã bỏ ngỏ khả năng VARCHARloại dữ liệu sẽ thay đổi trong bản phát hành trong tương lai để tuân thủ tiêu chuẩn SQL (đó là lý do tại sao mọi người sử dụng VARCHAR2trong Oracle vì hành vi của loại dữ liệu đó được đảm bảo sẽ tiếp tục như vậy).


60

Tom Kyte VP của Oracle:

Một varchar chiều dài ZERO được coi là NULL.

'' không được coi là NULL.

'' khi được gán cho char (1) trở thành '' (loại char là chuỗi đệm trống).

'' khi được gán cho varchar2 (1) trở thành '' là chuỗi có độ dài bằng 0 và chuỗi có độ dài bằng 0 là NULL trong Oracle (nó không dài '')


17
Wow, Tom thật đáng yêu. Cho rằng các câu hỏi liên quan đến sự khác biệt quá lớn từ SQL92, bạn sẽ nghĩ rằng mình sẽ bớt khó chịu hơn về điều đó ... mặc dù anh ta có thể mệt mỏi khi trả lời.
Chris R

8
Điều tốt nhất về Tom là bạn nhận được một câu trả lời rõ ràng, trong đó nêu chính xác những gì anh ấy nghĩ. Tìm kiếm một số ý kiến ​​trong đó mọi người đã sử dụng văn bản nói chuyện trên Ask Tom
Chris Gill

9
Nhưng sẽ chính xác hơn nếu dòng thứ hai được đổi thành '' không phải lúc nào cũng được coi là NULL.
ypercubeᵀᴹ

2
@ypercube Câu trích dẫn không chính xác hơn bằng cách thay đổi từ thực sự được sử dụng bởi Tom. Nếu bạn nghĩ Tom nói nó khó hiểu, mmm. Có lẽ. Tôi nghĩ rằng anh ấy tại chỗ . Các tình huống khó hiểu nhất phát sinh khi ''được chuyển đổi hoàn toàn thành VARCHAR2, chẳng hạn như cast('' as char(1)) is null... thật đáng ngạc nhiên
sehe

1
@sehe bit khó hiểu đối với tôi là chọn 1 từ kép trong đó ('' là null)
matt freake

20

Tôi nghi ngờ điều này có ý nghĩa hơn nhiều nếu bạn nghĩ về Oracle theo cách mà các nhà phát triển trước đó có thể đã làm - như một phần phụ trợ được tôn vinh cho một hệ thống nhập dữ liệu. Mỗi trường trong cơ sở dữ liệu tương ứng với một trường ở dạng mà toán tử nhập dữ liệu nhìn thấy trên màn hình của anh ta. Nếu toán tử không nhập bất cứ thứ gì vào một trường, cho dù đó là "ngày sinh" hay "địa chỉ" thì dữ liệu cho trường đó là "không xác định". Không có cách nào để một nhà điều hành chỉ ra rằng địa chỉ của ai đó thực sự là một chuỗi trống và điều đó thực sự không có ý nghĩa gì cả.


5
Điều đó chỉ có ý nghĩa nếu bạn cho rằng mọi trường trong hệ thống nhập dữ liệu là bắt buộc. Không trả lời cho trường không bắt buộc (ví dụ: "Tên của chó") là hợp lệ, do đó, một chuỗi trống vẫn có mục đích riêng biệt với NULL. Ngay cả với giả định đó, tôi nghi ngờ các nhà phát triển ban đầu nghĩ về Oracle như là một "phụ trợ được tôn vinh cho một hệ thống nhập dữ liệu" vì vậy tôi không chắc câu trả lời này có ý nghĩa gì cả.
Jared

19

Tài liệu của Oracle cảnh báo các nhà phát triển về vấn đề này, quay trở lại ít nhất là đến phiên bản 7.

Oracle đã chọn đại diện cho NULLS bằng kỹ thuật "giá trị không thể". Ví dụ: NULL ở vị trí số sẽ được lưu dưới dạng "trừ 0", một giá trị không thể. Bất kỳ số 0 nào trừ kết quả tính toán sẽ được chuyển thành số 0 dương trước khi được lưu trữ.

Oracle cũng đã chọn một cách sai lầm khi coi chuỗi VARCHAR có độ dài bằng không (chuỗi trống) là một giá trị không thể và là một lựa chọn phù hợp để đại diện cho NULL. Nó chỉ ra rằng chuỗi rỗng là xa một giá trị không thể. Đó thậm chí là danh tính dưới hoạt động nối chuỗi!

Tài liệu của Oracle cảnh báo các nhà thiết kế và phát triển cơ sở dữ liệu rằng một số phiên bản tương lai của Oracle có thể phá vỡ liên kết này giữa chuỗi rỗng và NULL và phá vỡ bất kỳ mã nào phụ thuộc vào liên kết đó.

Có các kỹ thuật để gắn cờ NULLS ngoài các giá trị không thể, nhưng Oracle đã không sử dụng chúng.

(Tôi đang sử dụng từ "vị trí" ở trên để chỉ giao điểm của một hàng và một cột.)


Tài liệu của Oracle cảnh báo các nhà thiết kế và phát triển cơ sở dữ liệu rằng một số phiên bản tương lai của Oracle có thể phá vỡ liên kết này giữa chuỗi rỗng và NULL và phá vỡ bất kỳ mã nào phụ thuộc vào liên kết đó - bạn có thể vui lòng cung cấp tài liệu tham khảo cho tuyên bố này không?
Piotr Dobrogost


2

Chuỗi rỗng giống như NULL đơn giản vì nó là "cái ác nhỏ hơn" khi so sánh với tình huống khi hai chuỗi (chuỗi rỗng và null) không giống nhau.

Trong các ngôn ngữ mà NULL và Chuỗi rỗng không giống nhau, người ta phải luôn kiểm tra cả hai điều kiện.


Đơn giản chỉ cần đặt not nullràng buộc trên cột của bạn và chỉ kiểm tra trên chuỗi trống.
Egor Skriptunoff

6
Kiểm tra cả hai điều kiện là không quan trọng: chỉ WHERE Field <> ''trả về true nếu trường không phải là NULL và không trống, trên cơ sở dữ liệu có hành vi ANSI cho chuỗi trống.

1

Theo tài liệu chính thức 11g

Cơ sở dữ liệu Oracle hiện xử lý một giá trị ký tự có độ dài bằng 0 là null. Tuy nhiên, điều này có thể không tiếp tục đúng trong các bản phát hành trong tương lai và Oracle khuyên bạn không nên coi các chuỗi rỗng giống như null.

Lý do có thể

  1. val IS NOT NULL dễ đọc hơn val != ''
  2. Không cần kiểm tra cả hai điều kiện val != '' and val IS NOT NULL

5
Trong cơ sở dữ liệu tuân thủ ANSI hoàn toàn, bạn không phải kiểm tra cả hai điều kiện. val <> ''đã loại trừ NULL. Có lẽ bạn có ý đó val = '' OR val IS NULL. Nhưng các chuỗi rỗng không so sánh như NULL là hữu ích !
ErikE

Tôi đồng ý với phần so sánh.
Sorter

0

Ví dụ từ cuốn sách

   set serveroutput on;   
    DECLARE
    empty_varchar2 VARCHAR2(10) := '';
    empty_char CHAR(10) := '';
    BEGIN
    IF empty_varchar2 IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_varchar2 is NULL');
    END IF;


    IF '' IS NULL THEN
    DBMS_OUTPUT.PUT_LINE(''''' is NULL');
    END IF;

    IF empty_char IS NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_char is NULL');
    ELSIF empty_char IS NOT NULL THEN
    DBMS_OUTPUT.PUT_LINE('empty_char is NOT NULL');
    END IF;

    END;

-1

Bởi vì không coi nó là NULL cũng không đặc biệt hữu ích.

Nếu bạn mắc lỗi trong lĩnh vực này trên Oracle, bạn thường chú ý ngay lập tức. Tuy nhiên, trong máy chủ SQL, nó sẽ xuất hiện để hoạt động và sự cố chỉ xuất hiện khi ai đó nhập một chuỗi trống thay vì NULL (có lẽ từ thư viện máy khách .net, trong đó null khác với "", nhưng bạn thường xử lý chúng giống nhau ).

Tôi không nói rằng Oracle đúng, nhưng dường như cả hai cách đều tệ như nhau.


2
Dễ dàng hơn nhiều để gỡ lỗi. Ngoài ra, nếu bạn thấy một ô trống hoặc đầu vào trên màn hình, bạn sẽ biết dữ liệu trong DB là null. Trong các DB khác có '' <> NULL, bạn không thể "nhìn thấy" nếu dữ liệu là null hoặc '', điều này dẫn đến các lỗi rất lén lút. '' = null đó là tùy chọn hợp lý nhất, ngay cả khi nó không chuẩn.
Lucio M. Tato

2
Trong các DB khác trong đó '' <> NULL, bạn không thể "nhìn thấy" nếu dữ liệu là null hoặc '' '= = Thông thường, các công cụ DB hiển thị các NULL khác với các chuỗi trống. Trên thực tế, ngay cả Nhà phát triển SQL của Oracle cũng hiển thị NULL như là ((null). Tôi đoán điều này là để phân biệt NULL với khoảng trắng nhưng nó không liên quan đến sự khác biệt giữa NULL và chuỗi rỗng.
Didier L

-6

Thật vậy, tôi không có gì ngoài những khó khăn khi giao dịch với Oracle, bao gồm các giá trị thời gian không hợp lệ (không thể được in, chuyển đổi hoặc bất cứ thứ gì, chỉ cần nhìn vào hàm DUMP ()) được phép chèn vào cơ sở dữ liệu, rõ ràng thông qua một số lỗi phiên bản của khách hàng như một cột nhị phân! Quá nhiều cho việc bảo vệ tính toàn vẹn của cơ sở dữ liệu!

Oracle xử lý các liên kết NULL:

http://digitalbush.com/2007/10/27/oracle-9i-null-behavior/

http://jeffkemponoracle.com/2006/02/empty-opes-andor-null.html


1
giá trị thời gian không hợp lệ? Không chắc điều đó có nghĩa là gì. Bạn đã đăng bài này như một câu hỏi ở đây?

1
Vấn đề stackoverflow trước ngày - Tôi không có thông tin hữu ích từ các diễn đàn của Oracle và tôi đã tạo ra một cách giải quyết - Tôi sẽ theo dõi các ghi chú của mình và đăng ở đây.
Cade Roux

Đăng chi tiết như một câu hỏi ở đây.
Cade Roux

-6

Trước hết, chuỗi null và null không phải lúc nào cũng được Oracle đối xử như nhau. Theo định nghĩa, một chuỗi null là một chuỗi không chứa ký tự. Điều này hoàn toàn không giống như một null. Theo định nghĩa, NULL không có dữ liệu.

Năm hoặc sáu năm trước, chuỗi null được Oracle đối xử khác với null. Trong khi, như null, chuỗi null bằng với mọi thứ và khác với mọi thứ (mà tôi nghĩ là tốt cho null, nhưng hoàn toàn SAI cho chuỗi null), ít nhất độ dài (chuỗi null) sẽ trả về 0, vì nó phải là chuỗi null một chuỗi có độ dài bằng không.

Hiện tại trong Oracle, độ dài (null) trả về null mà tôi đoán là OK, nhưng độ dài (chuỗi null) cũng trả về null hoàn toàn SAI.

Tôi không hiểu tại sao họ quyết định bắt đầu đối xử với hai "giá trị" riêng biệt này như nhau. Chúng có nghĩa là những thứ khác nhau và lập trình viên nên có khả năng hành động theo từng cách khác nhau. Việc họ đã thay đổi phương pháp của họ cho tôi biết rằng họ thực sự không có manh mối về cách xử lý các giá trị này.


Cần có trích dẫn để phân biệt giữa "chuỗi null" và giá trị NULL. Trong bất kỳ cơ sở dữ liệu nào ngoại trừ Oracle, một VARCHARtrường có thể có một giá trị (không hoặc nhiều ký tự) hoặc không có giá trị (NULL), dừng hoàn toàn.

"Năm hoặc sáu năm trước" từ năm 2011 sẽ rơi vào khung thời gian 10g (10.1 phát hành 2003, 10.2 vào năm 2005). 10g hoàn toàn không đưa ra bất kỳ thay đổi toàn cầu nào trong việc xử lý null và chưa bao giờ có sự phân biệt giữa NULLvà một chuỗi có giá trị null, và sự phân biệt như vậy không có ý nghĩa gì. Tôi sợ câu trả lời này là một tưởng tượng hoàn chỉnh.
William Robertson
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.