2

MYSQL 結合について学習しようとしていますが、これを理解するのに苦労しています。userID が特定のユーザーと関係がある table1 のすべての行を取得したいと考えています。

table2 にはユーザーの関係が含まれているため、userID は iduser1 フィールドまたは iduser2 フィールドのいずれかにある可能性があります。次のクエリを実行すると、正しい結果が得られます。

set @userID = 91;
SELECT * FROM table1
    WHERE (iduser IN (SELECT iduser1 FROM table2 WHERE iduser2 = @userID)
        OR (iduser IN (SELECT iduser2 FROM table2 WHERE iduser1 = @userID)))

table1: 
    iduser FK

table2:
    iduser1 FK
    iduser2 FK

MySQL のネストされたクエリは、パフォーマンスに関しては評判が悪いと言われており、何らかの方法で JOINS を使用してこの同じクエリを実行できると確信していますが、特に table1. iduser は、table2.iduser1 または table2.iduser2 のいずれかにすることができます

同じテーブルに 2 回参加するにはどうすればよいですか?

4

2 に答える 2

3

この式を考えると:

set @userID = 91;
SELECT * FROM table1
    WHERE (iduser IN (SELECT iduser1 FROM table2 WHERE iduser2 = @userID)
        OR (iduser IN (SELECT iduser2 FROM table2 WHERE iduser1 = @userID)))

EXISTS を使用すると、その 2 つのサブクエリを次のように減らすことができます。

set @userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
    select * from table2 z
    where (z.user2 = @userID and iduser1 = x.iduser)
       OR (z.user1 = @userID and iduser2 = x.iduser)
)

OR はクエリの速度を低下させる可能性がありますが、RDBMS では必ずしも短絡するとは限りません。その場合は、CASE WHEN を使用して短絡を試みる必要があります。OR を使用すると実行に 5 秒かかるクエリがありましたが、CASE WHEN に変換すると 0 秒未満でした:

set @userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
    select * from table2 z
    where 
       CASE WHEN z.user2 = @userID THEN
           IF(z.iduser1 = x.iduser, 1, 0)
       CASE WHEN z.user1 = @userID THEN 
           IF(z.iduser2 = x.iduser, 1, 0)
       END = 1
)

ブール式は自動的に整数 (0(false) または 1(true)) にキャストされるため、次のようにすることもできます。

set @userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
    select * from table2 z
    where 
       CASE WHEN z.user2 = @userID THEN
           z.iduser1 = x.iduser
       CASE WHEN z.user1 = @userID THEN 
           z.iduser2 = x.iduser
       END = 1
)

またはこれ:

set @userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
    select * from table2 z
    where 
       CASE WHEN z.user2 = @userID THEN
           z.iduser1 = x.iduser
       CASE WHEN z.user1 = @userID THEN 
           z.iduser2 = x.iduser
       END 
)

MySQL を使用していない場合は、次のようにします。

set @userID = 91;
SELECT * FROM table1 x
WHERE EXISTS(
    select * from table2 z
    where 
       CASE WHEN z.user2 = @userID THEN
           CASE WHEN z.iduser1 = x.iduser THEN 1 END
       CASE WHEN z.user1 = @userID THEN 
           CASE WHEN z.iduser2 = x.iduser THEN 1 END
       END = 1
)
于 2012-05-27T07:22:23.210 に答える
0

MySQL は、サブクエリだけでなく、EXISTS や OR の処理も不十分であることに異議を唱えさせてください。したがって、私は問題に対する別のアプローチを提案します。

クエリのパラメーターはユーザー変数のおかげでわかっているため、結合可能なクエリを準備できます。

set @userID = 91;

SELECT DISTINCT T1.* FROM table1 T1
LEFT JOIN (SELECT iduser1 FROM table2 WHERE iduser2 = @userID) T21 
ON (T1.iduser = T21.iduser1)
LEFT JOIN (SELECT iduser2 FROM table2 WHERE iduser1 = @userID) T22 
ON (T1.iduser = T22.iduser2)
;

ご覧のとおり、EXISTS と OR は LEFT JOIN によって完全に実装されています。この LEFT JOIN は、2 番目のテーブル内の他のユーザーとの一致があればそれを検索します。明らかに、table1 の同じユーザーが複数の一致を見つける可能性があるため、DISTINCT がトリックを実行して重複を削除する可能性があります。

MySQL を活用するために、できる限り JOIN を使用することをお勧めします。

于 2012-05-28T07:31:10.500 に答える