2012-10-04 11 views
6

Ich habe mehrere Tabellen, die ich versuche, einige Daten aus zu bekommen, und ich bin sehr nah dran, kann aber den Deal nicht ganz schließen.Benötigen SQL-Guru für eine komplexe Abfrage

Ich habe die folgenden Tabellen:

  • EVENT
  • USER
  • FREUND
  • USER__FRIEND
  • EVENT__INVITATION

User und Freundin über die USER__FRIEND Tabelle verknüpft sind (die enthält ein USER_ID- und ein FRIEND_ID-Feld

EVENT__INVITATION verbindet ein Ereignis mit einem Freund (es hat EVENT_ID und INVITEE_ID)

ich alle Veranstaltungen zu bekommen versuchen, wo:

  • ich der EVENT Schöpfer bin ($ myuserid = EVENT.CREATOR_ID)
  • oder ich bin zu der Veranstaltung eingeladen ($ myuserid = EVENT__INVITATION.INVITEE_ID)
  • oder einer meiner Freunde ist der Schöpfer des Ereignisses ($ myuserid = USER__FRIEND.USER_ID uND EVENT.CREATOR_ID IN (die Liste meiner Freunde))
  • oder einer meiner Freunde zum EVENT ($ myuserid = USER__FRIEND.USER_ID UND EVENT__INVITATION.INVITEE_ID IN (die Liste meiner Freunde))

Es gibt einige andere WHERE-Bedingungen um andere Parameter eingeladen wird, aber ich denke, Ich kann diese selbständig sortieren.

Im Moment war der einzige Weg, wie ich das zum Laufen bringen konnte, mit einer UNION, von der ich denke, dass sie eine Ausrede sein muss, und wenn ich bessere Chops hätte, könnte ich damit umgehen.

Also, die Frage ist, kann dies mit einer einzigen, kostengünstigen Abfrage, die keine UNION verwendet getan werden? Hier

ist, was ich habe, so weit, die alles außer den Ereignissen erreicht, dass meine Freunde eingeladen werden (23 ist die übergebene Benutzer-ID in diesem Fall):

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 

und dies ist die Abfrage mit der 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 
); 

Es gibt mehr zu der Abfrage, die die Verwendung der UNION unerwünscht macht. Ich habe eine komplexe trig-Berechnung, die ich in der Hauptauswahl mache, und ordne die Ergebnisse nach diesem Wert. Ich denke, kann die Ergebnismenge durcheinander bringen.

Danke für jede Hilfe !!

+0

Sind Sie sicher, dass Sie nicht diejenigen vermissen, in denen der Freund der Schöpfer ist? – CrazyCasta

+0

Ich weiß, es fühlt sich männlicher an, alles in einem großen Join zu machen, aber ich vermute, dass die UNION effizienter ist. – Barmar

+0

@Crazy: Nein, dass da drin ist (schau dir das letzte OR der WHERE-Klausel an). – Raconteur

Antwort

3

Wie über die folgenden:

-- 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 (oder war die Antwort von Chase?) - Sorry für die Verspätung ... RL ist in die Quere gekommen. Müssen einige Daten erstellen, um dies auf Herz und Nieren zu prüfen, aber ich denke, es wird funktionieren. Wird als Antwort akzeptieren, sobald ich es getestet habe. Prost! – Raconteur

+0

Die Antwort kam von Chase, ich habe gerade einen Tippfehler im SQL behoben. – Barmar

+0

Danke Chase und Barmar. Das war nicht genau das, was ich brauchte, aber ich bekam definitiv 90% des Weges dorthin, und ich konnte es abschließen. Schätze deine Hilfe und Ausdauer! – Raconteur

0

ich bei der Abfrageoptimierung derzeit nicht sehr gut bin, so würde ich nur so etwas wie dieses einen Versuch geben und lassen Sie die optimiser seine Mühe geben in die besten herauszufinden Weg, um die Ergebnisse zu bekommen:

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) 
; 

Wenn dies genug nicht effizient erweisen, können Sie immer mit so etwas wie @ChaseMedallion's suggestion gehen könnte, wie es in der Tat ein besseres für Ihren Fall könnte sich herausstellen.