2010-02-19 32 views
8

Tôi gặp vấn đề này. Cho một bảng users đó bao gồm tên của người sử dụng trong một mạng xã hội và friends bảng có chứa tên của người dùng và FRIENDNAME của người dùng như dưới đây ...Oracle SQL cách viết câu lệnh sql để xác minh xem người dùng trong mạng của tôi (tức là bạn bè hoặc bạn của bạn bè)

username friendname 

John  Thomas 
Chris  James 

... Tôi đang cố gắng để viết một câu lệnh SQL điều đó sẽ xảy ra nếu người dùng ở trong mạng của tôi. Nói cách khác, là người dùng hoặc một người bạn của bạn bè?

Tôi đã nhảy múa xung quanh vấn đề này và chỉ có thể đưa ra câu hỏi này:

SELECT f2.username, f2.friendname 
FROM friends f2 
WHERE f2.username IN (
     SELECT f1.friendname 
     FROM friends f1 
     WHERE f1.username = 'Thomas') 
AND f2.friendname <> 'user1' 
AND f2.friendname = 'user2';  

Nó cơ bản kiểm tra xem người dùng nếu là một người bạn của bạn tôi nghĩa là chỉ trả về null nếu sai.

Cố gắng tìm hiểu cách tôi có thể mở rộng để trải qua tất cả mạng lưới bạn bè của mình. Ý tôi không chỉ là bạn của bạn tôi.

Trả lời

5
SELECT * 
FROM (
     SELECT username 
     FROM friends 
     START WITH 
       username = 'myname' 
     CONNECT BY 
       friendname = PRIOR username 
       AND level <= 3 
     ) 
WHERE username = 'friendname' 
     AND rownum = 1 

Cập nhật mức độ cần thiết: bạn có thể tìm kiếm các lớp bạn bè thứ ba, vv

Nếu mối quan hệ tình bạn là đối xứng, bạn nên thực hiện các truy vấn sau đây:

WITH q AS 
     (
     SELECT username, friendname 
     FROM friends 
     UNION ALL 
     SELECT friendname, username 
     FROM friends 
     ), 
     f AS 
     (
     SELECT friendname, level 
     FROM q 
     START WITH 
       username = 'Thomas' 
     CONNECT BY NOCYCLE 
       username = PRIOR friendname 
     ) 
SELECT * 
FROM f 
WHERE friendname = 'Jo' 
     AND rownum = 1 

Truy vấn này có thể được thực hiện nhanh hơn nhiều nếu bạn chuẩn hóa bảng của mình: lưu trữ hai bản ghi trên mỗi tình bạn, như sau:

CREATE TABLE dual_friends (orestes NOT NULL, pylades NOT NULL, CONSTRAINT pk_dualfriends_op PRIMARY KEY (orestes, pylades)) ORGANIZATION INDEX 
AS 
SELECT username, friendname 
FROM friends 
UNION ALL 
SELECT friendname, username 
     FROM friends 

Sau đó, bạn chỉ có thể thay thế CTE trên với dual_friends:

WITH f AS 
     (
     SELECT pylades, level 
     FROM dual_friends 
     START WITH 
       orestes = 'Thomas' 
     CONNECT BY NOCYCLE 
       orestes = PRIOR pylades 
       AND level <= 3 
     ) 
SELECT * 
FROM f 
WHERE pylades = 'Jo' 
     AND rownum = 1 

, mà sẽ sử dụng các chỉ số và có hiệu quả hơn, đặc biệt là nếu bạn giới hạn mức đối với một số giá trị hợp lý.

+0

Tuy nhiên oracle có truy vấn hierarchial sử dụng kết nối bởi như vậy sẽ làm mức độ tìm kiếm bạn – Mark

+0

sql Đó dường như để làm việc cho tôi. ok, hãy tưởng tượng cho bảng này tên người dùng tên người bạn Thomas Alice Alice Bob Bob Jo Chạy sql với myname = Thomas và friendname = 'Jo' không đưa ra điều gì cho biết Jo không nằm trong mạng Thomas, không chính xác –

+0

@user: Is mối quan hệ tình bạn của bạn đối xứng? Nghĩa là, nếu 'Alice' là bạn của Thomas, thì 'Thomas' cũng là bạn của' Alice'? Tôi tin anh ấy, nhưng tốt hơn là chỉ định nó. – Quassnoi

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