5

Xin lỗi cho tiêu đề, thật khó để giải thích.MySQL: Hai quan hệ n: 1, nhưng không phải cả hai cùng một lúc

Tôi cần một mô hình dữ liệu tương tự như sau: alt text

Như bạn có thể thấy, một tập thể thuộc về cả một người dùng hoặc một trường học. Vấn đề của tôi: Nó chỉ nên được cho phép thuộc về một người dùng HOẶC một trường học. Nhưng không bao giờ cả hai cùng một lúc.

Làm cách nào để giải quyết vấn đề này?

+0

Bạn muốn sử dụng đồ họa nào? – basszero

+0

@basszero: MySQL Workbench –

+0

wow! Đó là một chặng đường dài kể từ lần cuối cùng tôi thử nó! – basszero

Trả lời

6

Thiết kế hiện tại của bạn được gọi là vòng cung độc quyền trong đó bảng sets có hai khóa ngoài và cần chính xác một trong số đó là không rỗng. Đây là một cách để thực hiện các mối liên kết đa hình, vì một khoá ngoại đã cho chỉ có thể tham khảo một bảng đích.

Một giải pháp khác là tạo một "siêu phổ biến" chung mà cả hai tham chiếu usersschools, sau đó sử dụng làm phụ huynh của sets.

create table set_owner 

create table users 
    PK is also FK --> set_owner 

create table schools 
    PK is also FK --> set_owner 

create table sets 
    FK --> set_owner 

Bạn có thể nghĩ về điều này như tương tự với một giao diện trong mô hình OO:

interface SetOwner { ... } 

class User implements SetOwner { ... } 

class School implements SetOwner { ... } 

class Set { 
    SetOwner owner; 
} 

Re bình luận của bạn:

Vì vậy, các bảng SetOwner chứa cả userIds và SchoolID, đúng không? Điều đó có nghĩa là tôi sẽ không được phép có cùng một ID cho người dùng và trường học. Làm thế nào tôi có thể thực thi điều này?

Để bảng SetOwners tạo giá trị id. Bạn phải chèn vào SetOwners trước khi bạn có thể chèn vào Người dùng hoặc Trường học. Vì vậy, hãy tạo id trong Số người dùng và trường học không tự động tăng thêm; chỉ sử dụng giá trị được tạo bởi SetOwners:

INSERT INTO SetOwners DEFAULT VALUES; -- generates an id 
INSERT INTO Schools (id, name, location) VALUES (LAST_INSERT_ID(), 'name', 'location'); 

Bằng cách này, giá trị id đã cho sẽ không được sử dụng cho cả trường học và người dùng.

Nếu tôi muốn nhận loại chủ sở hữu cho tập hợp, tôi có cần thuộc tính ownerType trong bảng SetOwner của tôi không?

Bạn chắc chắn có thể làm điều này. Trong thực tế, có thể có các cột khác chung cho cả Người dùng và Trường học, và bạn có thể đặt các cột này trong SetOwners siêu cấp. Điều này được đưa vào mẫu Class Table Inheritance của Martin Fowler.

Và nếu tôi muốn lấy tên trường hoặc người dùng (tùy theo loại nào), tôi có thể thực hiện điều này bằng một truy vấn hay không? để có được tên)?

Bạn cần tham gia. Nếu bạn đang truy vấn từ một Tập hợp nhất định và bạn biết nó thuộc về một người dùng (không phải trường học), bạn có thể bỏ qua việc tham gia vào SetOwners và tham gia trực tiếp với Người dùng. Tham gia không nhất thiết phải đi bằng các khóa ngoại.

SELECT u.name FROM Sets s JOIN Users u ON s.SetOwner_id = u.id WHERE ... 

Nếu bạn không biết liệu một tập hợp thuộc về một tài khoản hoặc một trường, bạn sẽ phải làm một bên ngoài tham gia vào cả hai:

SELECT COALESCE(u.name, sc.name) AS name 
FROM Sets s 
LEFT OUTER JOIN Users u ON s.SetOwner_id = u.id 
LEFT OUTER JOIN Schools sc ON s.SetOwner_id = sc.id 
WHERE ... 

Bạn biết rằng SetOwner_id phải phù hợp với một hoặc bảng khác, Người dùng hoặc Trường học, nhưng không phải cả hai.

+0

Cảm ơn lời giải thích tuyệt vời. Cách tiếp cận với siêu âm có vẻ tương tự như cách mà geofflane đề xuất trong bình luận của ông. Tôi nghĩ tôi đã hiểu khái niệm ngay bây giờ. Vì vậy, bảng 'SetOwner' chứa cả UserID và SchoolID, đúng không? Điều đó có nghĩa là tôi sẽ không được phép có cùng một ID cho người dùng và trường học. Làm thế nào tôi có thể thực thi điều này? –

+0

Và một khía cạnh khác: ERD hiện tại trông giống như http://imgur.com/vD1ln.png này.Nếu tôi muốn lấy kiểu chủ sở hữu cho một tập hợp, tôi có cần thuộc tính ownerType trong bảng SetOwner của tôi không? Hay có cách nào khác để làm điều đó? Và nếu tôi muốn lấy tên của trường hoặc người dùng (tùy theo loại nào), tôi có thể làm điều này với một truy vấn hay tôi cần hai truy vấn (đầu tiên lấy loại và thứ hai để lấy tên)? –

+0

Chỉnh sửa tuyệt vời, cảm ơn bạn. Đó là lý do tại sao tôi yêu Stackoverflow. Chỉ có một câu hỏi còn lại: Tôi có thể sử dụng một cách an toàn 'LAST_INSERT_ID()' trong môi trường nhiều người dùng hoặc các truy vấn và chèn của người dùng khác có can thiệp vào truy vấn hiện tại để LAST_INSERT_ID thay đổi không? –

1

Bạn sẽ phải sử dụng trình kích hoạt để thực thi quy tắc kinh doanh này, vì MySQL có nhưng không thực thi ràng buộc CHECK (trên bất kỳ công cụ nào).

2

Với báo trước: Nó không hoàn toàn rõ ràng về những gì một Set trong mô hình dữ liệu của bạn.

Tôi đang đặt câu hỏi cho mô hình dữ liệu của bạn.

Tại sao người dùng -> Bộ và trường -> Bộ phải trỏ đến cùng một bảng. Nó không được chuẩn hóa hơn nếu đó là những tập dữ liệu độc lập. Chỉ vì họ chia sẻ một số điểm tương đồng trong các cột mà họ theo dõi không có nghĩa là chúng nên được lưu trữ trong cùng một bảng. Có phải chúng hợp lý giống nhau không?

Chỉ cần tạo các bảng riêng cho Bộ trường học và cho Bộ người dùng. Điều này sẽ làm cho các truy vấn nghịch đảo dễ dàng hơn vì bạn sẽ không phải kiểm tra các mối quan hệ rỗng trong bảng Sets để biết nếu nó thực sự là một UserSet hoặc một SchoolSet.

+0

Cảm ơn gợi ý. Trên thực tế các bộ (nhiều vocabs làm cho một bộ) là chính xác như nhau, họ chỉ có thể có chủ sở hữu khác nhau, hoặc là một trường học hoặc một người sử dụng. Như một bộ sẽ không bao giờ được chuyển từ một trường học thuộc về một người dùng hoặc ngược lại, tôi có thể chỉ cần tạo hai loại bộ và sao chép dữ liệu vào bảng khác khi cần thiết. Vấn đề với cách tiếp cận này là, sau đó tôi sẽ cần hai loại vocabs, và tôi không thực sự nghĩ rằng sẽ có nhiều ý nghĩa. –

+0

Bạn có thể đặt bảng SetOwner ở giữa Người dùng/Trường học và Bộ. Sau đó, mỗi bảng có thể 'sở hữu' một Set sẽ có một cột FK thành set_owner_id. Bảng Set sau đó cũng sẽ có set_owner_id. Về cơ bản, một người dùng và một trường học có mối quan hệ 1: 1 với SetOwner và SetOwner là 1: m để Đặt. Sau đó, mọi thứ đều có tính toàn vẹn tham chiếu thực thi. Điều đó sẽ làm cho nó khá khó khăn để đi từ Set to Owner (hợp lý) mặc dù. – geofflane

+0

Ý bạn là như thế này? http://i.imgur.com/dVRs9.png Tôi thực sự không hiểu cách giải quyết vấn đề này. –

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