我目前正在做一个有mysql查询的项目。项目中的所有mysql查询都是由另一位开发人员完成的。无论如何,我对他在下面所做的查询有点困惑:
SELECT MIN(s_date) AS s_date,
client_id
FROM tb1
WHERE flag = 1
AND client_id NOT IN (
SELECT DISTINCT client_id
FROM tb1
WHERE flag = 0
)
GROUP BY client_id;
查询的第一部分是检查标志是否为1,第二部分是检查NOT IN(标志为0)。我认为这有点多余,因为flag=1,它不可能是0。我不明白那个查询的逻辑。而且我认为NOT IN有点慢(我的数据库需要2秒)。
请解释一下这个查询是什么意思,以及我如何简化和改进它。
您似乎在总结标志从不为0
的客户端。查询更简单地写为:
SELECT MIN(s_date) s_date,
client_id F
FROM tb1
WHERE flag in (0, 1)
GROUP BY client_id
HAVING SUM(flag = 0) = 0;
这也可以提高性能。
在大多数数据库中,使用"not In"简单、直观,但速度较慢。有时你可以这样解决:
where myfield in
(select myfield
where I want it
minus
select myfield
where I want to exclude it)
有些数据库使用except而不是减号。我认为这不适用于mySql,所以你必须做这样的事情:
select somefields
from sometables
left join (
select idfield, someOtherField
from blah
where I want to exclude it
) temp on sometable on sometable.idfield = temp.idfield
and temp.someOtherField is null
以下是您的看法:
在子选择中,您可以找到至少有一条flag=0的记录的client_id的列表。
然后从主查询中排除该id列表。
所以,如果你有这样的样本数据:
client_id flag s_date
--------- ---- ------
1 1 2014-01-01
2 0 2014-02-01
2 1 2014-03-01
3 0 2014-04-01
4 1 2014-05-01
4 1 2014-06-01
您的查询只会返回:
s_date client_id
------ ---------
2014-01-01 1
2014-05-01 4
实际上,在您的查询中,flag
的冗余使用实际上在主查询中。根本不需要它,因为您已经消除了子select中所有具有flag=0值的client_id。
至于优化查询。这是其中一种情况,可能子选择比连接更快,也可能不是。它实际上取决于数据的行数、满足子选择条件的行数等(当然,假设所有适当的索引都已到位)。
你可以尝试这样的自加入,看看哪一个对你更好:
SELECT
MIN(a.s_date) AS s_date,
a.client_id AS client_id
FROM tbl AS a LEFT JOIN (
SELECT DISTINCT client_id
FROM tb1
WHERE flag = 0
) AS b
ON a.client_id = b.client_id
WHERE b.client IS NULL
GROUP BY a.client_id
也可以尝试@GordonLinoff的回答,这是获得相同查询结果的另一个创造性选项