2009-06-06 38 views
10

Trong SQL, có cách nào để thực thi rằng chỉ một cột trong một nhóm cột có giá trị không và cột còn lại là rỗng? Có thể một ràng buộc hoặc kích hoạt? Loại điều này có thể là một bảng tra cứu, nhưng có bất kỳ thiết kế bảng thay thế nào có thể thực hiện điều này tốt hơn không?SQL: làm thế nào để thực thi rằng chỉ có một cột duy nhất được đặt trong một nhóm cột

Ví dụ:

ID OtherTable1ID OtherTable2ID OtherTable3ID 
----------------------------------------------------- 
1  23    NULL    NULL 
2  NULL    45    NULL 
3  33    55    NULL -- NOT ALLOWED 

Vấn đề chính là các cột này đều FKS đến các bảng khác, vì vậy tôi không thể sụp đổ chúng xuống một cột duy nhất.

Tôi đang sử dụng SQL Server, nhưng mọi câu trả lời đều sẽ thực hiện.

+0

Cảm ơn bạn đã cập nhật, nhưng bạn có thể muốn cung cấp thêm chi tiết về thiết kế cơ sở dữ liệu. Ví dụ, đây là một tình huống phụ, trong đó bảng này có thể là một kiểu con của một và chỉ một trong các bảng khác. Ngoài ra, có được phép cho tất cả các cột "Khác" không có giá trị không? –

+0

Trông giống như bảng tra cứu. Về cơ bản nó có nghĩa là nếu bạn thêm một FK nữa, bạn thêm một cột nữa vào nó? –

+0

Vâng, về cơ bản nó là một bảng tra cứu cho tôi. Nếu tôi cần thêm một tham số tra cứu khác, tôi phải thêm một cột FK khác. Có cách nào tốt hơn để đạt được điều này? –

Trả lời

13

@ ngại đề nghị tvanfosson của việc bật đèn xanh cho ba cột, nhưng đối với tính tổng quát tôi thích

(cast(col1 is not null, int) + 
cast(col2 is not null, int) + 
cast(col3 is not null, int)) = 1 

vì nó khái quát tốt hơn để bất kỳ số lượng các cột với các "tuyến tính phát triển" (thay vì "bậc hai đang phát triển") Lượng mã hóa (nó thậm chí còn neater trong phương ngữ SQL mà không yêu cầu rõ ràng đúc bit boolean aka để int, nhưng tôi không chắc chắn nếu SQL Server là một trong những người).

+4

Đối với SQL Server, điều này có khả năng sẽ làm việc tốt hơn ... (trường hợp khi col1 IS NOT NULL sau đó 1 else 0 end + case khi col2 IS NOT NULL thì 1 else 0 end <2) –

+1

@Glen Little: Đồng ý với cú pháp được cung cấp nhưng tôi nghĩ việc so sánh cho trường hợp của OP vẫn phải là '... = 1'. –

6

Một hạn chế như sau nên làm việc:

(column1 is null and column2 is null) 
    or (column1 is null and column3 is null) 
    or (column2 is null and column3 is null) 

này sẽ không ép buộc, nó chứa một cột không null, tuy nhiên. Để thực hiện điều đó, hãy thêm một ràng buộc khác:

column1 is not null 
    or column2 is not null 
    or column3 is not null 
0

Nghe có vẻ như bạn muốn sử dụng một cột cho tập hợp những thứ đó. Có lẽ bạn có thể sử dụng một số loại thẻ để nói rằng đó là một số Foo,3 hoặc Bar,7 hoặc Baz,9?

+0

Tôi nên làm rõ điều này trong câu hỏi của tôi, nhưng vấn đề tôi đang phải đối mặt là các cột là FKs đến các bảng khác. Hãy để tôi cập nhật câu hỏi của mình, xin lỗi –

+0

Ah, giờ đây nó thật thú vị! Hãy để tôi suy nghĩ về điều này một chút, nhưng nó âm thanh như thể nó về cơ bản là một vấn đề với một thực hiện RDBMS nghèo. Thật không may, theo nghĩa này, tôi không nghĩ rằng có một điều tốt ngoài kia ... –

+0

(Để làm rõ, không có lý do gì bạn không nên khai báo loại cột là "tham chiếu đến điều này , hoặc một tham chiếu đến điều đó, hoặc một tham chiếu đến khác, "với đầy đủ hỗ trợ FK trên tất cả điều đó, nhưng DBMS hiện tại đến hư không gần đó.) –

1
CREATE TABLE Repro.Entity 
(
    entityId INTEGER IDENTITY (1, 1) NOT NULL, 
    column1 INTEGER, 
    column2 INTEGER, 
    column3 INTEGER, 
    CONSTRAINT Entity_PK PRIMARY KEY(entityId), 
    CONSTRAINT Entity_CK CHECK(
     (column1 IS NOT NULL AND column2 IS NULL AND column3 IS NULL) OR 
     (column1 IS NULL AND column2 IS NOT NULL AND column3 IS NULL) OR 
     (column1 IS NULL AND column2 IS NULL AND column3 IS NOT NULL)) 
) 
1

Đối với tôi, có vẻ như đó là một quyết định thiết kế tồi. Vì ID là khóa chính trong bảng này, nó sẽ là một giá trị pháp lý cho tất cả các mối quan hệ khóa ngoại. Điều này có nghĩa là bạn phải làm việc tích cực hơn ở lớp giao diện/doanh nghiệp để đảm bảo rằng các giá trị nằm trong phạm vi được chấp nhận. Ví dụ, cách các bảng được thiết lập, nó hoàn toàn hợp pháp cho bảng 2 để sử dụng 1 làm giá trị tra cứu thay vì 2 nó được cho là sử dụng - và cơ sở dữ liệu sẽ không bẫy nó.

Tôi có thể sẽ không đi tuyến đường này. Tôi sẽ chỉ cần tạo một lược đồ có tên là tra cứu và sẽ tạo một bảng tra cứu cho mỗi giá trị tra cứu. Theo cách này, cơ sở dữ liệu sẽ thực thi đúng tất cả các ràng buộc.

Cách bạn đã thiết lập bảng tra cứu, bạn hiện bị giới hạn ở các khóa ngoài số nguyên. Trong một số trường hợp, đó có thể không phải là một ý tưởng hay - ví dụ bạn muốn lưu mã quốc gia/mã cho tiểu bang thay vì các giá trị số nguyên đại diện cho chúng.

+0

Tôi cũng thích tránh các cột NULLable nhưng thiết kế của OP (tùy thuộc vào ràng buộc làm việc theo yêu cầu) có lợi thế hơn bạn (giả sử tôi đã hiểu chính xác) ở chỗ chúng có thể viết một ràng buộc để thực thi chính xác một giá trị không NULL của bạn có thể có tình huống mà có thể không có hàng trong bảng tham chiếu, trừ khi bạn cuộn của riêng bạn 'phân phối các phím nước ngoài' (google Hugh Darwen) bằng cách sử dụng gây nên (hoặc tương tự). – onedaywhen

Các vấn đề liên quan