如何正确地向复杂的MySQL查询添加WHERE语句?

时间:2014-06-21 17:25:15

标签: mysql sql

我有一个非常复杂的查询来从数据库中获取一些数据,对它们进行排序并相应地对它们进行排序。

以下是它的SQL小提琴:SQL Fiddle

现在我要做的是,在此查询中添加WHERE语句,这样只会选择有限的用户(上面有3个用户,下面有3个用户,id = 8)。

WHERE sort BETWEEN @userpos - 3 AND @userpos + 3

所以看起来应该是这样的,但是第一个例子是:

SQL Fiddle

我已经尝试过对这个查询实现这个WHERE语句,但我无法弄明白我应该在哪里添加,因为我总是收到错误(无法找到该列)。

我的问题的任何建议和/或解决方案?我应该为此重写整个查询吗?

1 个答案:

答案 0 :(得分:1)

如果我理解正确,您可以使用子查询执行此操作:

SET @userid = 8

SELECT *
FROM (SELECT @pos := @pos + 1 AS sort, points, r.userid, s.active
      FROM rank r JOIN
           settings s
           USING (userid) CROSS JOIN
           (SELECT @pos := 0) p
      WHERE s.active = 1
      ORDER BY points DESC
    ) list 
WHERE userid = @userid;

请注意,这会消除您拥有的一个子查询层。否则,它与您的查询非常相似。

编辑:

以上内容更多地基于SQL Fiddle而不是问题。 (糟糕。)

要获得给定行之前和之后的三行是可能的,只需要一个小的调整,使用技巧。诀窍是用用户pos定义另一个变量,然后在外部查询中使用该变量:

SELECT *
FROM (SELECT @pos := @pos + 1 AS sort, points, r.userid, s.active,
             if(userid = @userid, @userpos := @pos, 0)
      FROM rank r JOIN
           settings s
           USING (userid) CROSS JOIN
           (SELECT @pos := 0, @userpos := 0) p
      WHERE s.active = 1
      ORDER BY points DESC
    ) list 
WHERE `sort` between @userpos - 3 and @userpos + 3;

注意:MySQL不保证select中变量的评估顺序。以下在执行顺序方面更安全:

SELECT *
FROM (SELECT (case when (@pos := @pos + 1) is NULL then NULL
                   when (case when (userid = @userid) then @userpos := @pos else 1 end) is null
                   then NULL
                   else @pos
              end) AS sort, points, r.userid, s.active,
             if(userid = @userid, @userpos := @pos)
      FROM rank r JOIN
           settings s
           USING (userid) CROSS JOIN
           (SELECT @pos := 0, @userpos := 0) p
      WHERE s.active = 1
      ORDER BY points DESC
    ) list 
WHERE `sort` between @userpos - 3 and @userpos + 3;

奇怪的case语句用于确保语句执行。 is null是为了确保when子句失败,因此分配是按顺序进行的。