Kiểm tra ràng buộc chỉ một trong ba cột là không null


61

Tôi có một bảng (Máy chủ SQL) chứa 3 loại kết quả: FLOAT, NVARCHAR (30) hoặc DATETIME (3 cột riêng biệt). Tôi muốn đảm bảo rằng đối với bất kỳ hàng nào, chỉ một cột có kết quả và các cột khác là NULL. Hạn chế kiểm tra đơn giản nhất để đạt được điều này là gì?

Bối cảnh cho việc này đang cố gắng cải thiện khả năng thu được các kết quả không phải là số vào một hệ thống hiện có. Thêm hai cột mới vào bảng với một ràng buộc để ngăn chặn nhiều hơn một kết quả trên mỗi hàng là cách tiếp cận kinh tế nhất, không nhất thiết là đúng.

Cập nhật: Xin lỗi, kiểu dữ liệu snafu. Đáng buồn là tôi đã không có ý định các loại kết quả được chỉ định để được hiểu là kiểu dữ liệu SQL Server, chỉ là các thuật ngữ chung, được sửa chữa ngay bây giờ.

Câu trả lời:


72

Sau đây nên làm thủ thuật:

CREATE TABLE MyTable (col1 FLOAT NULL, col2 NVARCHAR(30) NULL, col3 DATETIME NULL);
GO

ALTER TABLE MyTable
ADD CONSTRAINT CheckOnlyOneColumnIsNull
CHECK 
(
    ( CASE WHEN col1 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col2 IS NULL THEN 0 ELSE 1 END
    + CASE WHEN col3 IS NULL THEN 0 ELSE 1 END
    ) = 1
)
GO

24

Có thể bạn sẽ cần thực hiện ba bài kiểm tra trong giới hạn, một bài kiểm tra cho mỗi cặp mà bạn muốn là null và một bài kiểm tra cho cột không phải là null:

ALTER TABLE table
ADD CONSTRAINT CK_one_is_null
CHECK (
     (col1 IS NOT NULL AND col2 IS NULL AND col3 IS NULL)
  OR (col2 IS NOT NULL AND col1 IS NULL AND col3 IS NULL) 
  OR (col3 IS NOT NULL AND col1 IS NULL AND col2 IS NULL)
);

Đây không phải là khả năng mở rộng, tôi có một bảng có 9 khóa ngoại và chỉ có một khóa không phải là null, tôi thích giải pháp của
@MarkStoreySmith

5

Đây là một giải pháp PostgreSQL sử dụng các hàm mảng tích hợp :

ALTER TABLE your_table
ADD chk_only_one_is_not_null CHECK (array_length(array_remove(ARRAY[col1::text, col2::text, col3::text], NULL), 1) = 1);

Đây có phải là triển khai nhanh hơn trong postgreSQL so với các giải pháp CASE hoặc AND / OR đã đề cập trước đó được đăng bởi Mark Storey và mrdenny không?
Chris Britt
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.