繁体   English   中英

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

[英]Select in MySQL where all rows meet a condition

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

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

我想选择从未迟到的员工的所有UserID(早上9点或更早到达),这样做的最佳方法是什么?

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

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

尝试这个:

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

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

我查看了用于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

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

您可以获得结果更多3种方法用于此查询1.使用分组功能2.使用子查询3.使用连接......等

使用Group - By

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

GROUP BY用户ID

使用Sub Query With

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

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


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

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

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的答案。

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

比尔卡文建议:

尝试这个:

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'失败。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM