2013-03-31 25 views
5

Tôi có bảng MySQL cho Người dùng có khóa chính _id và tôi muốn đại diện cho tình bạn (hiển thị trên danh sách bạn bè của người dùng khác) dưới dạng bảng với cặp các khóa ngoài của người dùng. Tôi đang nghĩ đến một cái gì đó như:Khóa chính của SQL composite không có thứ tự (cặp số nguyên theo thứ tự phải là duy nhất)

CREATE TABLE UserFriendships (
    userIdA INT NOT NULL, 
    userIdB INT NOT NULL, 
    PRIMARY KEY (userIdA, userIdB), 
    FOREIGN KEY (userIdA) REFERENCES Users(_id) 
    FOREIGN KEY (userIdB) REFERENCES Users(_id) 
) 

Đó là sự hiểu biết của tôi rằng điều này sẽ cho phép cả hai (userIdA = 2, userIdB = 7)(userIdA = 7, userIdB = 2) được chèn như hàng riêng biệt. Tôi muốn một hàng cho mỗi tình bạn, đó là nói một hàng cho mỗi cặp userIds.

Có ai biết cách tôi có thể cải thiện điều này không? Ngay cả khi các ràng buộc trên được đáp ứng, để có được một danh sách của tất cả các bạn bè của người dùng foo tôi phải làm một công đoàn, một cái gì đó như: SELECT userIdB AS friendUserId WHERE userIdA = foo UNION SELECT userIdA WHERE userIdB = foo. Đây có phải là cách tốt nhất để thực hiện truy vấn đó hay tôi nên suy nghĩ về việc thay đổi lược đồ của mình?

+0

cách bạn đối phó với sự tương hỗ? – Strawberry

+4

Sẽ khá dễ dàng với bất kỳ DBMS nào khác, nhưng với MySQL tôi chỉ có thể nghĩ ra một giải pháp kích hoạt để ngăn chặn điều này. –

+0

@Strawberry Tôi đã không nghĩ về điều đó, nhưng tôi có thể bao gồm một bảng riêng biệt của FriendRequests mà, một lần đáp lại, kết quả là chèn vào UserFriendships. Mặc dù chúng sẽ chứa cùng một dữ liệu, do đó dường như không cần thiết ... –

Trả lời

4

Bạn có thể sử dụng một TRIGGER BEFORE INSERT để enfore một quy tắc kinh doanh:

  • userIdA phải lúc nào cũng cho người dùng ID thấp hơn và userIdB lúc nào cũng là người sử dụng với ID cao

Bằng cách này cả hai kết hợp (A, B) và (B, A) dẫn đến cùng một thứ tự cột với cùng một khóa chính.

DELIMITER | 
CREATE TRIGGER enforce_friendship_id_order BEFORE INSERT ON UserFriendships 
    FOR EACH ROW BEGIN 
    SET @lowerId := IF(NEW.userIdA < NEW.userIdB, NEW.userIdA, NEW.userIdB); 
    SET @higherId := IF(NEW.userIdA > NEW.userIdB, NEW.userIdA, NEW.userIdB); 
    SET NEW.userIdA = @lowerId; 
    SET NEW.userIdB = @higherId; 
    END; 
| 
DELIMITER ; 
+0

Yikes. Upvote cho một giải pháp làm việc, nhưng tôi nghĩ rằng tôi muốn để lại các quy tắc unenforced và rủi ro trùng lặp hơn mess với gây nên. Tôi cho rằng đây là thứ họ đang làm, nhưng nó không cảm thấy sạch sẽ, bạn biết không? –

+1

tốt, vâng, đây là một trong các trường hợp sử dụng trình kích hoạt. tôi không thấy sự thay đổi trong lược đồ bảng có thể giúp bạn như thế nào, đó là lý do tại sao tôi đăng câu trả lời này. bạn có thể có cùng quy tắc kinh doanh trong mã ứng dụng của mình, nhưng tôi nghĩ nó thuộc về cơ sở dữ liệu. MySQL không phải là một trợ giúp thực sự ở đây. – Kaii

+0

@MikeTurley là "gây rối" với trình kích hoạt quá tệ, thực sự? – Kaii

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