MySQL计数(*)不计算结果行
实现订阅模型的m:n关系的简化模式:MySQL计数(*)不计算结果行,mysql,sql,Mysql,Sql,实现订阅模型的m:n关系的简化模式: CREATE TABLE c ( id INT(11) PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32) ) ENGINE=MyISAM CHARACTER SET=UTF8; CREATE TABLE t ( id INT(11) PRIMARY KEY AUTO_INCREMENT, name VARCHAR(32) ) ENGINE=MyISAM CHARACTER SET=UTF8; CRE
CREATE TABLE c (
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32)
) ENGINE=MyISAM CHARACTER SET=UTF8;
CREATE TABLE t (
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(32)
) ENGINE=MyISAM CHARACTER SET=UTF8;
CREATE TABLE c2t (
id INT(11) PRIMARY KEY AUTO_INCREMENT,
cid INT(11) NOT NULL,
tid INT(11) NOT NULL,
dateStart DATE NULL,
dateEnd DATE NULL
) ENGINE=MyISAM CHARACTER SET=UTF8;
INSERT INTO c (name) VALUES ('mike'),('carl'),('suzy');
INSERT INTO t (name) VALUES ('plan1'),('plan2'),('plan3'),('plan4');
INSERT INTO c2t (cid, tid, dateStart, dateEnd) VALUES
(1, 1, '2014-01-01', '2014-07-31'),
(1, 2, '2014-08-01', '2015-07-31'),
(1, 1, '2015-08-01', null),
(1, 3, '2015-09-01', null),
(2, 1, '2014-01-01', '2015-07-31'),
(2, 2, '2015-08-01', '2015-09-30'),
(2, 3, '2015-09-30', null),
(3, 1, '2014-01-01', '2014-12-31'),
(3, 2, '2014-01-01', '2014-12-31'),
(3, 3, '2015-01-01', '2015-10-31'),
(3, 4, '2015-01-01', '2015-10-31');
我开发了一个查询来查找拥有t的活动订阅的c:
SELECT c.*
FROM c
LEFT JOIN c2t ON c.id = c2t.cid
AND NOW() BETWEEN COALESCE(dateStart, '0000-00-00')
AND COALESCE(dateEnd, DATE_ADD(NOW(), INTERVAL 1 DAY))
GROUP BY c2t.cid
HAVING COUNT(c2t.id) > 0;
结果如预期:
id name
1 mike
2 carl
当我试图计算结果行时,问题就出现了。查询几乎相同,我刚刚输入了一个计数(*):
结果:
`COUNT(*)`
2
1
预期结果将是包含找到的行数(2)的单行。我只能假设小组正在干预,但不知道如何解决。非常欢迎解释。用子查询包装所有内容,并在外部查询中使用
COUNT
:
SELECT COUNT(*)
FROM (
SELECT c.*
FROM c
LEFT JOIN c2t ON c.id = c2t.cid
AND NOW() BETWEEN COALESCE(dateStart, '0000-00-00')
AND COALESCE(dateEnd, DATE_ADD(NOW(), INTERVAL 1 DAY))
GROUP BY c2t.cid
HAVING COUNT(c2t.id) > 0
) AS sub
如果您只想返回具有活动订阅的c的数量,那么您可以简化查询,如下所示:
SELECT COUNT(DISTINCT c.id) AS cnt
FROM c
INNER JOIN c2t ON c.id = c2t.cid
AND NOW() BETWEEN COALESCE(dateStart, '0000-00-00')
AND COALESCE(dateEnd, DATE_ADD(NOW(), INTERVAL 1 DAY))
因此,内部连接
被用来代替左连接
:不需要返回在c2t
中没有匹配项的c,因为它们不会有任何活动订阅
此外,不需要按分组:查询只返回一行c的数目
最后,
DISTINCT
必须在COUNT
中使用,以避免重复的c.id
值多次计数。只是一个改进,而不是使用COUNT(*)尝试在该表中使用一个键,例如:COUNT(主键)将提高您的查询性能,尤其是在使用innodb时。@csf包装的SELECT会从子查询表中的索引中受益吗?@Willyde Check查询优化器(至少在SQL Server世界中)足够聪明,可以在COUNT(1)/COUNT(*)/COUNT(pk)
SELECT COUNT(DISTINCT c.id) AS cnt
FROM c
INNER JOIN c2t ON c.id = c2t.cid
AND NOW() BETWEEN COALESCE(dateStart, '0000-00-00')
AND COALESCE(dateEnd, DATE_ADD(NOW(), INTERVAL 1 DAY))