2

我正在尝试了解 MYSQL 联接,但无法弄清楚这一点。我想获取 table1 中 userID 与给定用户有关系的所有行。

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.x 有一个 OR 语句。 iduser 可以在 table2.iduser1 或 table2.iduser2 中

我怎样才能加入同一张桌子两次?

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,您可以将这两个子查询减少为以下内容:

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 时需要不到零秒:

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(假)或 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 = 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 完美实现,它与第二个表中的其他用户搜索每个匹配项(如果有)。显然,table1 中的同一用户可以找到多个匹配项,因此 DISTINCT 可能会解决问题并删除重复项。

我建议您尽可能使用 JOIN 来利用 MySQL。

于 2012-05-28T07:31:10.500 回答