MySQL中NOT EXISTS的替代方法,因为查询需要时间来执行NOT EXISTS

时间:2017-03-29 22:10:26

标签: php mysql

虚拟餐桌:

id   FileName    DateLastSaved
1    Marium.doc    2015-01-01
2    Amna.doc      2016-01-01
3    Marium.doc    2016-01-01

我希望查询返回FileName在整个表中唯一的行。应返回特定日期范围的行。 假设日期范围仅为2016,因此不应返回第三行,因为FileName不是唯一的。

我创建的查询是:

$presentquery="SELECT * FROM InitialLog i WHERE MDid='$MDid' AND 
(DateLastSaved>='$firstdate' AND DateLastSaved<='$presentdate') AND NOT
 EXISTS (SELECT id FROM InitialLog i2  WHERE i2.id<i.id AND i.FileName=i2.FileName )"; 

(其中$ firstdate和$ presentdate是日期范围的2个日期)

查询返回准确的结果,但需要时间来执行。有没有其他方法可以重写这个查询??

(我有很多行的表)

3 个答案:

答案 0 :(得分:0)

您可以使用LEFT JOIN获取相同的逻辑并查找空值,即

$presentquery = "SELECT DISTINCT i.* FROM InitialLog i
LEFT JOIN InitialLog i2 ON i2.id<i.id AND i.FileName=i2.FileName
WHERE i.MDid='$MDid'
AND i.DateLastSaved>='$firstdate'
AND i.DateLastSaved<='$presentdate'
AND i2.id IS NULL";

这样您就可以进行单个连接,而不是对i中的每个值进行子查询。

答案 1 :(得分:0)

我把这个查询放在一起,它很快就会返回结果。

Select *
FROM foo
Where (`datelastsaved` > '2015-12-31' && `datelastsaved` < '2017-01-01')
    AND `filename` NOT IN (
         Select `filename`
         FROM foo
         GROUP BY `filename`
         HAVING COUNT(*) > 1);

第一部分是你的普通select语句,其中where子句用于过滤日期。

第二部分是NOT IN,其中select语句找到所有具有重复文件名的文件。

Select `filename`  FROM foo GROUP BY `filename` HAVING COUNT(*) > 1)

答案 2 :(得分:0)

看起来您正在尝试获取与每个文件名首次出现相关的数据,这应该有效:

SELECT * 
FROM InitialLog i 
WHERE MDid='$MDid' 
   AND DateLastSaved>='$firstdate' 
   AND DateLastSaved<='$presentdate'
   AND id IN (SELECT MIN(id) FROM InitialLog GROUP BY FileName)
;

或者,您可以使用相同的子查询来执行JOIN:

SELECT i.* 
FROM InitialLog AS i 
   INNER JOIN (SELECT MIN(id) AS id 
               FROM InitialLog 
               GROUP BY FileName
   ) AS firsts USING (id)
WHERE i.MDid='$MDid' 
   AND i.DateLastSaved>='$firstdate' 
   AND i.DateLastSaved<='$presentdate'
;