我有一个非常复杂的查询来从数据库中获取一些数据,对它们进行排序并相应地对它们进行排序。
以下是它的SQL小提琴:SQL Fiddle
现在我要做的是,在此查询中添加WHERE
语句,这样只会选择有限的用户(上面有3个用户,下面有3个用户,id = 8)。
WHERE sort BETWEEN @userpos - 3 AND @userpos + 3
所以看起来应该是这样的,但是第一个例子是:
我已经尝试过对这个查询实现这个WHERE语句,但我无法弄明白我应该在哪里添加,因为我总是收到错误(无法找到该列)。
我的问题的任何建议和/或解决方案?我应该为此重写整个查询吗?
答案 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
子句失败,因此分配是按顺序进行的。