0

「ユーザー」と「関係」の 2 つのテーブルがあり、すべてのユーザーの関係を選択したいと考えています。

table relations
user1 user2
1     2
1     3
5     1

上記の例のテーブルでは、ids が users テーブルに関連付けられています。

たとえば、ユーザー ID 1 のすべての関係を選択して、彼の友人の名前を結合したいのですが、戻りが期待されます。

id   name
2    demo friends1
3    demo friends2
5    demo friends3

だから私が試したこと: -

Select (case user1='1' then r.user2 else r.user1 end) as id,u.name from relations r
join users u on u.id = (case r.user1='1' then r.user2 else r.user1 end)
where (user1 = 1 or user2= 2);

これは私が推測したいものに近いです。誰かが私が間違っていることを明確にすることができますか? それを行うより良い方法はありますか?

4

2 に答える 2

0

あなたの構造を考えると、それを行う1つの方法は次のとおりです。

SELECT users.id, users.name
FROM relations
INNER JOIN users ON relations.user2 = users.id
WHERE relations.user1 = 1
UNION ALL
SELECT users.id, users.name
FROM relations
INNER JOIN users ON relations.user1 = users.id
WHERE relations.user2 = 1

これは、重複する行を含めないように注意を払っていることを前提としています。user1これを確認する 1 つの方法は、常に より小さくなければならない制約を確立することuser2です。複合一意キー ( user1user2) を使用します。これはおそらく PK です。

この場合、格納されるデータは次のように変更されます。

ユーザー1 ユーザー2
1 2
1 3
1 5

理解を完全にするために、あなたが望むことを達成するための他の方法があります. このクエリは、ユニオンが最外層ではなく派生テーブルで取得されることを除いて、最初のクエリとほとんど同じです。ただし、優れたクエリ オプティマイザーは 2 つを同じものとして認識する場合があります。

SELECT users.id, users.name
FROM users
INNER JOIN
(
    SELECT user1 AS id FROM relations WHERE user2 = 1
    UNION ALL
    SELECT user2 AS id FROM relations WHERE user1 = 1
) friends ON users.id = friends.id

または、次のような本当に醜いクエリで、あなたの試みに似ています。これは間違いなく遅くなり、お勧めしません (CASEORは余分な処理ステップであり、処理が遅くなり、インデックスの使用が無効になる可能性があります)。

SELECT users.id, users.name
FROM users
INNER JOIN
(
    SELECT CASE WHEN user1 = 1 THEN user2 ELSE user1 END AS id
    FROM relations
    WHERE user1 = 1 OR user2 = 1
) friends ON users.id = friends.id

これらのクエリの結果を見て、EXPLAINどれが最適かを判断できます。

于 2013-07-06T16:55:16.983 に答える