[英]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
索引的优化计划,并说:
Using index; Using temporary
” 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');
Using where; Using index
” Using where
” 这似乎最有可能获得最佳表现。 不可否认,我的测试表中只有四行,所以这不是代表性的测试。
您可以获得结果更多3种方法用于此查询1.使用分组功能2.使用子查询3.使用连接......等
SELECT userID,MAX(ArrivalTime)as latest FROM ArrivalTimes WHERE latest <='9:00:00'
从用户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.