底线
使用COUNT(field) 或COUNT(*),并坚持使用它,如果您的数据库允许COUNT(tableHere) 或COUNT(tableHere.*),请使用它。
简而言之,不要将COUNT(1) 用于任何事情。它是一头小马,很少做你想做的事,在极少数情况下相当于count(*)
使用count(*) 进行计数
使用* 处理所有需要计算所有内容的查询,即使是连接,使用*
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
但不要将COUNT(*) 用于左连接,因为即使从属表与父表中的任何内容都不匹配,它也会返回 1
SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
不要被那些建议在 COUNT 中使用 * 时,它会从您的表中获取整行,说 * 很慢的人所迷惑。 SELECT COUNT(*) 和 SELECT * 上的 * 彼此无关,它们是完全不同的东西,它们只是共享一个共同的标记,即 *。
另一种语法
事实上,如果不允许将字段命名为与其表名相同,RDBMS 语言设计器可以赋予COUNT(tableNameHere) 与COUNT(*) 相同的语义。示例:
为了计算行数,我们可以这样:
SELECT COUNT(emp) FROM emp
他们可以让它变得更简单:
SELECT COUNT() FROM emp
对于 LEFT JOIN,我们可以这样:
SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
但他们不能这样做 (COUNT(tableNameHere)),因为 SQL 标准允许使用与其表名相同的名称来命名字段:
CREATE TABLE fruit -- ORM-friendly name
(
fruit_id int NOT NULL,
fruit varchar(50), /* same name as table name,
and let's say, someone forgot to put NOT NULL */
shape varchar(50) NOT NULL,
color varchar(50) NOT NULL
)
用 null 计数
此外,如果字段名称与表名称匹配,则将字段设为可为空也不是一个好习惯。假设您在 fruit 字段上有值 'Banana'、'Apple'、NULL、'Pears'。这不会计算所有行,它只会产生 3,而不是 4
SELECT count(fruit) FROM fruit
虽然一些 RDBMS 采用这种原则(为了计算表的行数,它接受表名作为 COUNT 的参数),但这将在 Postgresql 中工作(如果下面两个表中的任何一个中都没有 subordinate 字段,即只要字段名和表名没有名字冲突):
SELECT boss.boss_id, COUNT(subordinate)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
但是,如果我们在表中添加 subordinate 字段,以后可能会造成混淆,因为它将计算字段(可以为空),而不是表行。
为了安全起见,请使用:
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
count(1): 一招制胜的小马
尤其是COUNT(1),它是一个一招制胜的小马,它只适用于一个表查询:
SELECT COUNT(1) FROM tbl
但是当您使用连接时,该技巧不适用于多表查询而不会混淆其语义,尤其是您不能编写:
-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
那么这里的 COUNT(1) 是什么意思呢?
SELECT boss.boss_id, COUNT(1)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
这是……吗?
-- counting all the subordinates only
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
还是这个……?
-- or is that COUNT(1) will also count 1 for boss regardless if boss has a subordinate
SELECT boss.boss_id, COUNT(*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
仔细想想,你可以推断出COUNT(1) 和COUNT(*) 是一样的,不管是什么类型的join。但是对于 LEFT JOIN 的结果,我们不能将 COUNT(1) 塑造成:COUNT(subordinate.boss_id), COUNT(subordinate.*)
所以只需使用以下任一方法:
-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.boss_id)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
在 Postgresql 上工作,很明显你想计算集合的基数
-- count the subordinates that belongs to boss
SELECT boss.boss_id, COUNT(subordinate.*)
FROM boss
LEFT JOIN subordinate on subordinate.boss_id = boss.boss_id
GROUP BY boss.id
另一种计算集合基数的方法,非常类似于英语(只是不要创建名称与其表名相同的列):http://www.sqlfiddle.com/#!1/98515/7
select boss.boss_name, count(subordinate)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name
你不能这样做:http://www.sqlfiddle.com/#!1/98515/8
select boss.boss_name, count(subordinate.1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name
你可以这样做,但这会产生错误的结果:http://www.sqlfiddle.com/#!1/98515/9
select boss.boss_name, count(1)
from boss
left join subordinate on subordinate.boss_code = boss.boss_code
group by boss.boss_name