2017-07-30 40 views
0

我有这样的查询:如何根据select语句中的值限制结果?

SELECT u.id, u.name, top_tags(u.id) as top_tags, cal_rep(u.id) rep 
FROM users 
ORDER BY rep 
LIMIT :p,20; 

top_tags()是返回要么NULL或用户的前三名标签的逗号分隔字符串的函数。另外cal_rep()是另一个函数,它返回0或声望数。所以上面的查询总是返回一个列表全部用户。事情是这样的:

+----+----------+-------------------------------+-----------+ 
| id | name |   top_tags   | rep | 
+----+----------+-------------------------------+-----------+ 
| 1 | Jack  | HTML,CSS,jQuery    | 3244  | 
| 2 | Peter | SQL-Server,MySQL,Database  | 543  | 
| 3 | Martin | NULL       | 0   | 
+----+----------+-------------------------------+-----------+  

虽然我想省略谁拥有NULL他们的top_tags0声誉的用户。所以这是预期的结果:

+----+----------+-------------------------------+-----------+ 
| id | name |   top_tags   | rep | 
+----+----------+-------------------------------+-----------+ 
| 1 | Jack  | HTML,CSS,jQuery    | 3244  | 
| 2 | Peter | SQL-Server,MySQL,Database  | 543  | 
+----+----------+-------------------------------+-----------+  

我该怎么做?

回答

1

您可以在WHERE子句中使用相同的表达式。

SELECT u.id, u.name, top_tags(u.id) as top_tags, cal_rep(u.id) rep 
FROM users 
WHERE top_tags(u.id) IS NOT NULL 
    AND cal_rep(u.id) <> 0 
ORDER BY rep 
LIMIT :p,20; 

不知道,如果你想ANDOR

如果您不想重复SELECT子句中的表达式,则可以在HAVING子句中使用它们的别名。

SELECT u.id, u.name, top_tags(u.id) as top_tags, cal_rep(u.id) rep 
FROM users 
HAVING top_tags IS NOT NULL 
    AND rep <> 0 
ORDER BY rep 
LIMIT :p,20; 

关于性能:在表100万个整数我已经测试了下面的查询(MySQL的5.7.18)序列:

select i 
from helper.seq 
-- 0.265 sec 

select length(sha2(sha2(i, 512), 512)) as l 
from helper.seq 
-- 1.843 sec 

select length(sha2(sha2(i, 512), 512)) as l 
from helper.seq 
where length(sha2(sha2(i, 512), 512)) = 128 
-- 3.437 sec 

select length(sha2(sha2(i, 512), 512)) as l 
from helper.seq 
having l = 128 
-- 3.531 sec 

select * 
from (
    select length(sha2(sha2(i, 512), 512)) as l 
    from helper.seq 
) sub 
where l = 128 
-- 3.547 sec 

前两个查询比较,我们可以看到嵌套函数调用的开销约为1.6秒。对于其他三个查询,我们看到相同的开销增加了一倍。我不知道幕后发生了什么,但看起来MySQL不管方法如何都会执行两次函数。

+0

谢谢你......你认为你的第一个查询是最优的吗?既然你正在调用这个函数两次。在SELECT语句和WHERE子句中都是这样的。 –

+0

根据你的基准测试,我想将函数的结果初始化为一个变量,并且在查询中使用该变量两次会更好。 –

1

使用WHERE子句和is null运算符。

+0

谢谢.. upvote –

0
select * 
from (
    SELECT u.id, u.name, top_tags(u.id) as top_tags, cal_rep(u.id) rep 
    FROM users 
    LIMIT :p,20 
) a 
where a.top_tags is not null 
and a.rep != 0 
ORDER BY a.rep; 

这样,函数只执行一次。

+0

你已经尝试了同样的技巧[这里](https://stackoverflow.com/a/45403564/5563083)。这不会按预期工作,因为在过滤之前限制了结果。 –