MySQL, tốt hơn để chèn NULL hoặc chuỗi rỗng?


230

Tôi có một mẫu trên một trang web có nhiều lĩnh vực khác nhau. Một số lĩnh vực là tùy chọn trong khi một số là bắt buộc. Trong DB của tôi, tôi có một bảng chứa tất cả các giá trị này, tốt hơn hết là chèn một giá trị NULL hoặc một chuỗi trống vào các cột DB nơi người dùng không đặt bất kỳ dữ liệu nào?

Câu trả lời:


220

Bằng cách sử dụng, NULLbạn có thể phân biệt giữa "không có dữ liệu" và "đặt dữ liệu trống".

Một số khác biệt nữa:

  • Một LENGTHsố NULLNULL, một LENGTHcủa một chuỗi rỗng là 0.

  • NULLs được sắp xếp trước các chuỗi trống.

  • COUNT(message)sẽ đếm chuỗi rỗng nhưng không NULLs

  • Bạn có thể tìm kiếm một chuỗi rỗng bằng cách sử dụng một biến ràng buộc nhưng không tìm thấy a NULL. Truy vấn này:

    SELECT  *
    FROM    mytable 
    WHERE   mytext = ?

    sẽ không bao giờ phù hợp với một NULLtrong mytext, bất kể giá trị bạn vượt qua từ khách hàng. Để khớp NULLs, bạn sẽ phải sử dụng truy vấn khác:

    SELECT  *
    FROM    mytable 
    WHERE   mytext IS NULL

3
Nhưng cái nào bạn nghĩ là nhanh hơn? 0 hoặc NULL hoặc ""
Atul Dravid

8
trong InnoDB NULL chiếm ít không gian hơn
Timo Huovinen

37
Tôi nghĩ rằng đây là một câu trả lời ổn, nhưng nó cũng hoàn toàn bỏ qua yếu tố "thực hành tốt nhất" của câu hỏi và chỉ tập trung vào các sự kiện có liên quan (thứ tự và độ dài của NULL? Những vấn đề này không quan trọng). Trên hầu hết các kiểu nhập dữ liệu văn bản không có sự khác biệt giữa "không phản hồi" và "phản hồi trống", vì vậy tôi nghĩ đây là một câu hỏi tuyệt vời xứng đáng có câu trả lời tốt hơn.
Nick

6
NULL cũng hoạt động rất tốt khi trường UNIQUE được thiết lập. Ví dụ: nếu bạn có một lĩnh vực như Giấy phép lái xe để thêm số DL của người đó và anh chàng đó không có. Vì đó là một trường duy nhất, người đầu tiên không có Số DL sẽ được thêm nhưng không phải là trường tiếp theo vì nó sẽ gây ra lỗi về ràng buộc duy nhất. Vì vậy, NULL là tốt hơn.
Saifur Rahman Mohsin

1
@Quassnoi ah xin lỗi ... Ý tôi là, tại sao việc đặt giấy phép lái xe là duy nhất ...?
cedbeu

44

Một điều cần xem xét, nếu bạn từng có kế hoạch chuyển đổi cơ sở dữ liệu, là Oracle không hỗ trợ các chuỗi rỗng . Chúng được tự động chuyển đổi thành NULL và bạn không thể truy vấn chúng bằng các mệnh đề như WHERE somefield = ''.


11
Điều này nghe có vẻ cực kỳ khó chịu với tôi, ngay cả trên liên kết của bạn, vì vậy tôi đã thử nó. Trường không, được đặt thành '', orory bỏ qua nó. Báo cáo độ dài là null thay vì 0. Điều đó thật sai lầm. Phải có một số cách xung quanh này. Hãy nghĩ rằng tôi sẽ đăng bài này như một câu hỏi khác.
Steve B.

1
Steve B.: xem câu hỏi này: stackoverflow.com/questions/1171196/
Kẻ

Cảm ơn đã tham khảo, mặc dù tôi vẫn không hiểu lý do. Được đăng dưới dạng stackoverflow.com/questions/1268177/ Mạnh
Steve B.

Có thể đáng để cập nhật câu trả lời để bao gồm thông tin từ liên kết được đăng bởi Quassnoi
SamuelKDavis

7
Peoplesoft (với Oracle DB) sử dụng một khoảng trắng để chỉ ra một giá trị trống. Vô cùng ngu ngốc. Họ cũng sử dụng 0,00025 để chỉ 0 cho FTE vì 0 không được phép. Sự lựa chọn đáng yêu đã được thực hiện trong sản phẩm đó.
JP Duffy

9

Một điều cần lưu ý là NULL có thể làm cho việc mã hóa của bạn khó khăn hơn nhiều. Trong Python chẳng hạn, hầu hết các bộ điều hợp cơ sở dữ liệu / ORMs ánh xạ NULLtới None.

Vì vậy, những thứ như:

print "Hello, %(title)s %(firstname) %(lastname)!" % databaserow

có thể dẫn đến "Xin chào, Không Joe Doe!" Để tránh nó, bạn cần một cái gì đó giống như mã này:

if databaserow.title:
    print "Hello, %(title)s %(firstname) %(lastname)!" % databaserow
else:
    print "Hello, %(firstname) %(lastname)!" % databaserow

Mà có thể làm cho mọi thứ phức tạp hơn nhiều.


25
Theo tôi, việc lạm dụng cơ sở dữ liệu của bạn để "sửa" các lỗi trong mã của bạn hoặc khung là một thực hành mã hóa (rất) xấu. Khi không có dữ liệu, bạn chỉ nên chèn NULL và nhất quán trong việc sử dụng dữ liệu đó. Nếu không, bạn phải sử dụng các câu lệnh như: if (myString == null || myString = ""). Khi một đối tượng không được đặt hoặc được xác định trong mã của bạn, bạn cũng đang sử dụng NULL thay vì một loại "giữ chỗ" nào đó (theo ý kiến ​​của tôi là một chuỗi trống).
Gertjan

5
Phụ thuộc rất nhiều vào ngôn ngữ của bạn lựa chọn. Trong Python "if not myString:" tests for none và "". Có lẽ chủ yếu là một vấn đề văn hóa. "Thực hành xấu" của Guy Guy là sự thanh lịch của người năng động.
tối đa

9

Tốt hơn để chèn tính NULLnhất quán trong cơ sở dữ liệu của bạn trong MySQL. Khóa ngoại có thể được lưu dưới dạng NULLnhưng KHÔNG phải là chuỗi rỗng.

Bạn sẽ có vấn đề với một chuỗi rỗng trong các ràng buộc. Bạn có thể phải chèn một bản ghi giả bằng một chuỗi trống duy nhất để đáp ứng ràng buộc Khóa ngoài. Tôi đoán thực hành xấu.

Xem thêm: Khóa ngoại có thể là NULL và / hoặc trùng lặp không?


Vấn đề ràng buộc đã làm tôi vấp ngã trong quá khứ vì vậy đó là lý do tại sao tôi "+1" câu trả lời này.
HPWD

Nhưng nếu bạn sử dụng NULL, hãy chắc chắn rằng bạn sẽ không bao giờ kết thúc với bất kỳ chuỗi trống nào. Dễ dàng thực hiện với nhiều công nghệ UI.
Tuntable

5

Tôi không biết cách thực hành tốt nhất ở đây là gì, nhưng tôi thường sẽ sai khi sử dụng null trừ khi bạn muốn null có nghĩa khác với chuỗi rỗng và đầu vào của người dùng khớp với định nghĩa chuỗi trống của bạn.

Lưu ý rằng tôi đang nói BẠN cần xác định cách bạn muốn chúng khác biệt. Đôi khi nó có ý nghĩa để có chúng khác nhau, đôi khi nó không. Nếu không, chỉ cần chọn một và gắn bó với nó. Như tôi đã nói, tôi có xu hướng ủng hộ NULL hầu hết thời gian.

Ồ, và hãy nhớ rằng nếu cột là null, thì bản ghi ít có khả năng xuất hiện trong thực tế bất kỳ truy vấn nào chọn (có mệnh đề where, theo thuật ngữ SQL) dựa trên cột đó, trừ khi lựa chọn dành cho cột null tất nhiên.


1
... Và bây giờ tôi thấy câu trả lời phía trên tôi, tôi nghĩ thật an toàn khi nói rằng sự khác biệt thông thường mà bạn sẽ quan tâm là không có dữ liệu so với dữ liệu trống. :-)
Bạch kim Azure

1

Nếu bạn đang sử dụng nhiều cột trong một chỉ mục duy nhất và ít nhất một trong số các cột này là bắt buộc (tức là trường biểu mẫu bắt buộc), nếu bạn đặt các cột khác trong chỉ mục thành NULL, bạn có thể kết thúc bằng các hàng trùng lặp. Đó là vì giá trị NULL bị bỏ qua trong các cột duy nhất. Trong trường hợp này, sử dụng các chuỗi trống trong các cột khác của chỉ mục duy nhất để tránh các hàng trùng lặp.

THU NHẬP TRONG MỘT INDEX ĐỘC ĐÁO:
(event_type_id, event_title, ngày, địa điểm, url)

VÍ DỤ 1:
(1, 'BBQ', '2018-07-27', null, null)
(1, 'BBQ', '2018-07-27', null, null) // được phép và sao chép.

VÍ DỤ 2:
(1, 'BBQ', '2018-07-27', '', '')
(1, 'BBQ', '2018-07-27', '', '') // KHÔNG được phép vì nó được sao chép.

Dưới đây là một số mã:

CREATE TABLE `test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `event_id` int(11) DEFAULT NULL,
  `event_title` varchar(50) DEFAULT NULL,
  `date` date DEFAULT NULL,
  `location` varchar(50) DEFAULT NULL,
  `url` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `event_id` (`event_id`,`event_title`,`date`,`location`,`url`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

Bây giờ chèn cái này để xem nó sẽ cho phép các hàng trùng lặp:

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-27', NULL, NULL);

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-27', NULL, NULL);

Bây giờ chèn cái này và kiểm tra xem nó không được phép:

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-28', '', '');

INSERT INTO `test` (`id`, `event_id`, `event_title`, `date`, `location`, 
`url`) VALUES (NULL, '1', 'BBQ', '2018-07-28', '', '');

Vì vậy, không có đúng hay sai ở đây. Tùy bạn quyết định điều gì phù hợp nhất với quy tắc kinh doanh của bạn.

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.