2012-10-04 36 views
6

Tôi có một số bảng mà tôi đang cố gắng lấy một số dữ liệu, và tôi rất gần, nhưng không thể hoàn toàn đóng giao dịch.Cần SQL guru cho một truy vấn phức tạp

tôi có các bảng sau:

  • EVENT
  • USER
  • BẠN BÈ
  • USER__FRIEND
  • EVENT__INVITATION

USER và BẠN BÈ được liên kết qua bảng USER__FRIEND (mà chứa trường USER_ID và FRIEND_ID)

EVENT__INVITATION liên kết một EVENT với một người bạn (nó có EVENT_ID và INVITEE_ID)

Tôi cố gắng để có được tất cả SỰ KIỆN nơi:

  • Tôi là tác giả EVENT ($ myuserid = EVENT.CREATOR_ID)
  • hay tôi mời tham dự sự kiện ($ myuserid = EVENT__INVITATION.INVITEE_ID)
  • hoặc một người bạn của tôi là tác giả của eVENT ($ myuserid = USER__FRIEND.USER_ID VÀ EVENT.CREATOR_ID IN (danh sách bạn bè của tôi))
  • hoặc một trong các bạn bè của tôi được mời tham dự EVENT ($ myuserid = USER__FRIEND.USER_ID VÀ EVENT__INVITATION.INVITEE_ID IN (danh sách bạn bè của tôi))

Có một số khác WHERE điều kiện xung quanh các thông số khác, nhưng tôi nghĩ Tôi có thể tự mình sắp xếp chúng.

Ngay bây giờ, cách duy nhất tôi có thể làm việc này là với UNION, điều mà tôi nghĩ phải là cảnh sát, và nếu tôi có tốt hơn thì tôi có thể sử dụng nó.

Vì vậy, câu hỏi đặt ra là, điều này có thể được thực hiện với một truy vấn đơn giản, rẻ tiền không sử dụng UNION không?

Dưới đây là những gì tôi có cho đến nay, trong đó hoàn thành tất cả mọi thứ ngoại trừ những sự kiện mà bạn bè của tôi được mời (23 được thông qua tại userID trong trường hợp này):

SELECT e.* 
FROM event e 
LEFT JOIN event__invitation ei ON ei.event_id = e.id 
LEFT JOIN user__friend uf ON uf.friend_id = ei.invitee_id 
LEFT JOIN friend f ON f.id = uf.friend_id 
WHERE (ei.invitee_id = 23 OR e.creator_id = 23 OR uf.user_id = 23 OR f.user_id = e.creator_id) 
AND e.start_time >= 1348000000 

và điều này là truy vấn với UNION:

SELECT e.* FROM event e 
INNER JOIN event__invitation ei ON ei.event_id = e.id 
INNER JOIN user__friend uf ON uf.friend_id = ei.invitee_id 
WHERE (e.creator_id = 23 OR ei.invitee_id = 23 OR uf.user_id = 23) 
UNION 
SELECT e1.* FROM event e1 
WHERE e1.creator_id IN (
    SELECT f1.user_id FROM friend f1 
    INNER JOIN user__friend uf1 ON uf1.friend_id = f1.id 
    WHERE uf1.user_id = 23 
    AND f1.user_id IS NOT NULL 
); 

Có nhiều truy vấn khiến việc sử dụng UNION không thể xóa. Tôi có một phép tính trig phức tạp mà tôi đang thực hiện trong lựa chọn chính và sắp xếp các kết quả theo giá trị đó. Tôi nghĩ có thể làm hỏng tập kết quả.

Cảm ơn bạn đã trợ giúp !!

+0

Bạn có chắc chắn bạn không bỏ lỡ những người mà bạn bè là người sáng tạo không? – CrazyCasta

+0

Tôi biết nó cảm thấy nam tính hơn để làm tất cả trong một cuộc tham gia lớn, nhưng tôi nghi ngờ UNION là hiệu quả hơn. – Barmar

+0

@Crazy: Không có ai trong đó (xem OR cuối cùng của mệnh đề WHERE). – Raconteur

Trả lời

3

Làm thế nào về những điều sau đây:

-- take only distinct events 
SELECT DISTINCT e.* 
-- start with the event 
FROM event e 
-- expand to include all invitees and their user_friend info 
LEFT JOIN event__invitation ei 
    ON ei.event_id = e.id 
LEFT JOIN user__friend invitee 
    ON invitee.friend_id = ei.invitee_id 
-- now we join again to user_friend to get the friends of the invitees/the creator 
LEFT JOIN user__friend invitedFriend 
    ON invitedFriend.user_id = invitee.user_id 
     OR invitedFriend.user_id = e.creator_id 
-- finally we match on whether any of these friends of friends are myself 
LEFT JOIN friend myselfAsAFriend 
    ON myselfAsAFriend.id = invitedFriend.friendId 
     AND myselfAsAFriend.userID = 23 
WHERE 
( 
    -- (1) I am the creator of the event 
    e.creator_id = 23 
    -- (2) I am invited to the event 
    OR invitee.user_id = 23 
    -- (3 and 4) for this join to match a friend of mine must be invited or the creator 
    OR myselfAsAFriend.id IS NOT NULL 
) 
AND e.start_time >= 1348000000 
+0

@Barmar (hoặc là câu trả lời từ Chase?) - Xin lỗi vì sự chậm trễ ... RL đã cản đường. Cần phải tạo ra một số dữ liệu để đưa nó qua các bước của nó, nhưng tôi nghĩ nó sẽ hoạt động. Sẽ chấp nhận câu trả lời ngay sau khi tôi được kiểm tra. Chúc mừng! – Raconteur

+0

Câu trả lời là từ Chase, tôi vừa sửa lỗi đánh máy trong SQL. – Barmar

+0

Cảm ơn Chase và Barmar. Đây không phải chính xác những gì tôi cần nhưng chắc chắn đã cho tôi 90 +% con đường ở đó, và tôi đã có thể bọc nó lại từ đó. Đánh giá cao sự giúp đỡ của bạn và sự kiên trì! – Raconteur

0

Tôi không giỏi điều chỉnh truy vấn hiện nay, vì vậy tôi sẽ chỉ cung cấp cho một cái gì đó như thế này thử và để optimizer để đặt nỗ lực của mình trong việc tìm ra sản phẩm tốt nhất cách để nhận được kết quả:

SELECT DISTINCT e.* 
FROM event e 
INNER JOIN event__invitation ei ON ei.event_id = e.id 
INNER JOIN (
    SELECT friend_id 
    FROM user__friend 
    WHERE user_id = $myUserID 
    UNION ALL 
    SELECT $myUserID 
) u ON u.friend_id IN (e.creator_id, ei.invitee_id) 
; 

Nếu điều này không chứng minh đủ hiệu quả, bạn luôn có thể đi với một cái gì đó giống như @ChaseMedallion's suggestion, vì nó thực sự có thể bật ra một tốt hơn một cho trường hợp của bạn.

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