6

私はいくつかのデータを取得しようとしているいくつかのテーブルを持っており、非常に近いですが、取引を完全に完了することはできません。

次のテーブルがあります。

  • イベント
  • ユーザー
  • 友達
  • USER__FRIEND
  • イベント__招待状

USER と FRIEND は、USER__FRIEND テーブル (USER_ID フィールドと FRIEND_ID フィールドを含む) を介してリンクされています。

EVENT__INVITATION は EVENT を FRIEND にリンクします (EVENT_ID と INVITEE_ID を持っています)

私はすべてのイベントを取得しようとしています:

  • 私はイベント作成者です ($myUserID = EVENT.CREATOR_ID)
  • または私はイベントに招待されています ($myUserID = EVENT__INVITATION.INVITEE_ID)
  • または私の友人の 1 人が EVENT の作成者です ($myUserID = USER__FRIEND.USER_ID AND EVENT.CREATOR_ID IN (私の友人のリスト))
  • または私の友人の 1 人がイベントに招待されました ($myUserID = USER__FRIEND.USER_ID AND EVENT__INVITATION.INVITEE_ID IN (私の友人のリスト))

他のパラメーターの周りには他にも WHERE 条件がいくつかありますが、それらは自分で整理できると思います。

今のところ、これを機能させる唯一の方法は、UNION を使用することでした。これは、対処する必要があると思います。より良いチョップがあれば、それを使用して回避できます。

問題は、UNION を使用しない単一の安価なクエリでこれを実行できるかということです。

ここに私がこれまでに持っているものがあります.これは、私の友人が招待されたイベントを除くすべてを達成します(この場合、23はユーザーIDで渡されます):

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

これは 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
);

UNION の使用を望ましくないものにするクエリは他にもあります。メインの選択で複雑な三角計算を行っており、その値で結果を並べ替えています。結果セットを台無しにする可能性があると思います。

助けてくれてありがとう!!

4

2 に答える 2

3

以下はどうでしょう。

-- 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
于 2012-10-05T00:32:57.413 に答える
0

現在、クエリチューニングはあまり得意ではないので、このようなものを試してみて、オプティマイザーに結果を得る最良の方法を見つけ出すように努力させます。

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

これが十分に効率的であることが証明されない場合は、 @ ChaseMedallionの提案のようなものをいつでも使用できます。これは、実際にあなたのケースに適したものになる可能性があるためです。

于 2012-10-08T06:26:14.387 に答える