在MySQL中选择所有行满足条件

时间:2009-02-11 19:13:50

标签: mysql select

在MySQL中,如何选择每行满足特定条件的数据?例如,假设我有一张表格显示员工何时到达工作岗位,它有三个字段:

CREATE TABLE ArrivalTimes
(UserID INT
,Day DATE 
,ArrivalTime TIME
);

我想选择所有从未迟到的员工的用户ID(早上9点或更早到达),最好的方法是什么?

5 个答案:

答案 0 :(得分:17)

@jjclarkson和@ davethegr8的答案很接近,但是你不能把聚合函数放在WHERE子句中。将为每一行评估WHERE子句。

您需要评估每个组的MAX()表达式,因此您需要使用HAVING子句。

试试这个:

SELECT UserID 
FROM ArrivalTimes
GROUP BY UserID
HAVING MAX(ArrivalTime) <= '09:00:00';

@MBCook评论HAVING可能很慢。你是对的,它可能不是产生预期结果的最快捷方式。但HAVING解决方案是 clear 。在某些情况下,性能的优先级低于清晰度和可维护性。

我查看了HAVING解决方案的EXPLAIN输出(在MySQL 5.1.30上):没有使用索引,额外的注释说“Using temporary; Using filesort”,这通常意味着性能不佳。

考虑以下问题:

SELECT DISTINCT a1.UserID
FROM ArrivalTimes a1
  LEFT OUTER JOIN ArrivalTimes a2 
  ON (a1.UserID = a2.UserID AND a2.ArrivalTime > '09:00:00')
WHERE a2.UserID IS NULL;

这会生成一个优化计划,该计划使用UserID上的索引并说:

  • a1:“Using index; Using temporary
  • a2:“Using where; Distinct

最后,以下查询生成一个优化计划,该计划似乎最有效地使用索引,并且没有临时表或文件排序。

SELECT DISTINCT a1.UserID
FROM ArrivalTimes a1
WHERE NOT EXISTS (SELECT * FROM ArrivalTimes a2 
                  WHERE a1.UserID = a2.UserID 
                    AND a2.ArrivalTime > '09:00:00'); 
  • a1:“Using where; Using index
  • a2:“Using where

这似乎最有可能获得最佳表现。不可否认,我的测试表中只有四行,所以这不是代表性的测试。

答案 1 :(得分:1)

这是一个很好的想法,但它不起作用。

SELECT UserID FROM ArrivalTimes WHERE MAX(ArrivalTime) <= '09:00:00' GROUP BY UserID

使用此查询,您将收到错误消息:“无效使用组功能”

根据定义,COUNT,MAX,MIN,AVG,SUM等聚合函数在一组(或一组记录)上执行它们的功能,因此MAX(ArrivalTime)需要采用以下形式:

GROUP BY UserID HAVING MAX(ArrivalTime) <= '09:00:00'

见上面@Bill Karwin的答案。

答案 2 :(得分:1)

SELECT userID, MAX(ArrivalTime) as latest
FROM ArrivalTimes 
WHERE latest <= '9:00:00'
GROUP BY userID

答案 3 :(得分:1)

Bill Karwin建议:

  

试试这个:

SELECT UserID 
FROM ArrivalTimes
GROUP BY UserID
HAVING MAX(ArrivalTime) <= '09:00:00';
  

我查看了用于HAVING解决方案的EXPLAIN输出(在MySQL 5.1.30上):没有使用索引,额外的注释说“使用临时;使用filesort”,这通常意味着性能很差。

我认为以下内容更清楚,因为有一个用户表,ArrivalTimes.UserId是一个外键。这将选择所有从不迟到的用户:

 select * from user a 
 where '09:00:00' 
  >= all( select ArrivalTime from ArrivalTime b where b.UserID = a.ID);

选择任何迟到的用户:

 select * from user a 
 where '09:00:00' 
  < any( select ArrivalTime from ArrivalTime b where b.UserID = a.ID);

这更清楚,因为它更符合我们的英语/自然语言规范。

它避免了group by的低效率;在MySql 5.0.51下,它需要临时或文件输出,就像Bill的那样。

(请注意,它确实需要将常量时间值置零,因此:'09:00:00'; '9:00:00'失败。)

答案 4 :(得分:1)

您可以为此查询获取更多3种方法的结果 1.使用分组功能 2.使用子查询 3.使用加入......等等。

使用Group - By

SELECT userID,MAX(ArrivalTime)为最新版本 来自ArrivalTimes 最新的&lt; ='9:00:00'

GROUP BY userID

使用Sub Query With

从用户a中选择*  '09:00:00'

  

= all(从ArrivalTime b中选择ArrivalTime,其中b.UserID = a.ID);


你也可以使用自我内部联接来获取它