我有一个SQL查询(在MySQL中),它选择一个总数和一个已完成任务有多少表的计数:
SELECT
count(*) as total, IF(SUM(NOT `completed`) IS NULL,0,SUM(NOT `completed`)) as incomplete
FROM
tasks
表格可以是:
CREATE TABLE `tasks` (
`clave` int(11) NOT NULL AUTO_INCREMENT,
`completed` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'If it is 0 isn\'t completed, otherwise is completed',
PRIMARY KEY (`clave`)
) ENGINE=InnoDB;
您可以在查询中观察到我已经使用了SUM(NOT completed)
两次,一次检查它是否将返回null(并返回0),另一次返回计数(当它不为空时)。如果表(或查询)为空,则SUM()
函数返回null
,即表格根本没有行。
当您尝试SUM两次时,我认为MySQL会计算两次总和。
我已经测试过如果我可以为列设置别名然后在IF中使用它,那么mysql不需要重新计算它。
作为一项要求,不完整的列在任何情况下都不能为空(例如,如果表任务为空)。
我的问题,效率如何? MySQL是否需要每次重新计算总和还是记住它?
答案 0 :(得分:4)
这可能是更好的方法,因为您对效果的计算量较少
使用发布的richard模式 - 请参阅FIDDLE
SELECT
total,
num_complete,
total - num_complete as num_incomplete
FROM(
SELECT
COUNT(*) as total,
SUM(IF(t.completed > 0, 1, 0)) as num_complete
FROM status_log t
) as t
检查每个OP请求的空表
SELECT
total,
num_complete,
total - num_complete as num_incomplete
FROM(
SELECT
COUNT(*) as total,
IF(COUNT(*) > 0, SUM(IF(t.completed > 0, 1, 0)), 0) as num_complete
FROM status_log t
) as t
你应该用另一种编程语言检查空表或空表 ...一般来说SQL应该用来从表中查询..不是在它是空的时候......如果它是完全空的,那么在用另一种编程语言运行此查询时应该检查空响应。这将大大提高它的性能。
答案 1 :(得分:2)
效率(或缺乏效率)将更多地与表中存在的索引以及存储引擎本身有关。同样,结果是否存储在缓存中将更多地与存储引擎有关,而不是与您正在编写的语句有关。
如果我在基于INNODB的存储引擎上写这个,我会做以下事情:
SELECT
count(*) as total,
SUM(CASE WHEN completed = 0 OR completed IS NULL THEN 1 ELSE 0 END) AS incomplete
FROM tasks;
我会将我的“已完成”列编入索引以便执行此操作。
我将从“IF”更改为case-when的原因主要是代码可移植性。 CASE WHEN如果需要,将更容易移动到其他数据库。
此外,完成的索引将允许此查询简单地评估索引,而不是表值本身。使用LRU,应该为您提供充足的效率。
答案 2 :(得分:2)
以下是使用CASE
语句的解决方案。您可以从单个SQL语句中获取两个聚合值。第二个查询示例显示了CASE
语句与直接聚合查询语句相比如何为您提供数据透视输出:
[SQL Fiddle][1]
MySQL 5.5.32架构设置:
CREATE TABLE status_log
(
id int auto_increment primary key,
type varchar(20),
status varchar(30)
);
INSERT INTO status_log
(type, status)
VALUES
('Alpha', 'COMPLETE'),
('Bravo', 'INCOMPLETE'),
('Charlie', 'INCOMPLETE'),
('Delta', 'COMPLETE'),
('Echo', 'COMPLETE'),
('Foxtrot', 'INCOMPLETE'),
('Golf', 'COMPLETE'),
('Hotel', 'COMPLETE')
查询1 :
SELECT count(1) as count_by_status, status
FROM status_log
GROUP BY status
<强> Results 强>:
| COUNT_BY_STATUS | STATUS |
|-----------------|------------|
| 5 | COMPLETE |
| 3 | INCOMPLETE |
查询2 :
SELECT count(*) as total_count,
sum(case when status = 'COMPLETE' then 1
else 0 end) as completed_count,
sum(case when status = 'INCOMPLETE' then 1
else 0 end) as incomplete_count
FROM status_log
<强> Results 强>:
| TOTAL_COUNT | COMPLETED_COUNT | INCOMPLETE_COUNT |
|-------------|-----------------|------------------|
| 8 | 5 | 3 |
答案 3 :(得分:0)
如果您将其设置为内嵌视图,则可以从查询中多次选择,如下所示:
SELECT total, incomplete, incomplete
FROM
(
SELECT
count(*) as total, IF(SUM(NOT `completed`) IS NULL,0,SUM(NOT `completed`)) as incomplete
FROM
tasks
) incomplete_count;
如果您从子查询或内联视图中多次选择,则MySQL不必重新计算它。此外,您可以在外部查询中执行任何其他操作/过滤器。
答案 4 :(得分:-1)
感谢John Ruddell和PhoneixS的澄清。这是一个使用CASE WHEN的版本:
select
count(*),
sum(
case completed
when 1 then 1
else 0
end) 'completed',
sum(
case when completed is null then 1
else 0
end) 'incomplete'
from tasks;