count(X) 函数用于计算一个查询所返回的行数,但是和其他的聚合函数AVG(X), SUM(X), MAX(X), MIN(X)一样,它在统计的时候都会简单的忽略含有空记录的查询,即count(X)中的表达式X的值为null时,count(X)(的返回值)为0。
例如,假设表test的内容如下:
select * from test;
ID NAME COUNTRY
--- ------------ ----------------
1 tone china
2 lily america
null null null
null null null
3 null china
则
SQL>select t.* ,count(name)from test t group by id,name;
ID NAME COUNT(NAME)
--- ------------ ----------------
1 tone 2
2 lily america
null null 0
3 null 0虽然(id,name)=(3 , null )这一组有一行,(id,name)=(null , null )这一组有两行,但是由于他们在name这一列值都是为null,所以count(name)的值就是0。同时,也说明虽然(id,name)=(null , null )这一组id和name值都是null,但是group by不会忽略该空记录组。
SQL>select t.* ,count(*)from test t group by id,name;
ID NAME COUNT(*NAME)
--- ------------ ----------------
1 tone 2
2 lily america
null null 2
3 null 1我们发现,使用count(*)时,(id,name)=(null , null )这一组的count(*name)的值就=为2,说明此时count(*)里的*所代表的表达式的值不为null,也就是说*不等价于表里的所有列的值(如果该值的数据类型不是字符类型,应该都会隐式转换为字符)连接成的字符串,具体到表test上,就是*不等价于id||name||country。
count(X) 函数里的参数个数只有一个,所以类似count(id,name) 时,就会提示“参数个数无效”。参数值为null时就不统计该值的。若想在count(X) 函数里出现表的多个字段,则使用如下方式:
例如,表test有字段ID,NAME ,COUNTRY,我们想在count(X) 函数里出现表test的ID,NAME 字段,则用count(id||name)的形式。其中,id||name就是一个参数,若id和name同时为null,则id||name也为null,故而被count(X) 函数统计。||是字符串连接符,连接多个字符串组成一个新的字符串。具体结果如下:
SQL>select t.* ,count(id||name) from test t group by id,name;
ID NAME COUNT(ID||NAME)
--- ------------ ----------------
1 tone 2
2 lily america
null null 0
3 null 1
总结:
1、count(column)不统计null。
而count(*) 和count(rowid)没有类似的问题,不会只统计非空记录。也可以用例如count(1),即count(数字或是字符常量或是字符串常量),不过還是用rowid快。
COUNT(*) operation countsall rows fed to it by execution plan branch under it.
COUNT(*) operation统计表对应的段中所有的数据行(包括其上各列的值为空值null的数据行)
COUNT(column) operation on the other handcountsall non-null values in that column from rows fed to it by execution plan branch under it.
COUNT(column) operation统计表对应的段中其列上的值不为空值null的数据行。
参见:
Select COUNT(*) and COUNT(column) are different things!
疑问:
在同一张表上,Count(*)和count(常量)如count(1),count(‘f’)两种形式的写法统计出来的结果都是一致的,能说明Count(*)和count(常量)如count(1),count(‘f’)等的原理是一样的?
这个要看具体的执行计划。
参见:
differenct between count(0), count(1) and count(*)[哪个执行速度快?]
2、count(*)查询所消耗的时间比count(rowid) 长吗?
count(*)也并不比count(rowid)慢,某些情况下比count(rowid)还要快得多,这个要看具体的执行计划。
(count(*)时走全表扫描方式,count(rowid)时索引范围扫描??)
参见:
differenct between count(0), count(1) and count(*)[哪个执行速度快?]
https://community.oracle.com/thread/523654?start=15&tstart=0
http://oracledba.co.uk/tips/count_speed.htm
3、关于*的疑问:
select * from test;
ID NAME COUNTRY
貌似说明,*等价于id||name||country。
而
SQL>select t.* ,count(*)from test t group by id,name;
ID NAME COUNT(*NAME)
--- ------------ ----------------
1 tone 2
2 lily america
null null 2
3 null 1
我们发现,使用count(*)时,(id,name)=(null , null )这一组的count(*name)的值就=为2,说明此时count(*)里的*所代表的表达式的值不为null,也就是说*不等价于表里的所有列的值(如果该值的数据类型不是字符类型,应该都会隐式转换为字符)连接成的字符串,具体到表test上,就是*不等价于id||name||country。
那么,*具体代表什么呢?*等价于id||name||country||rowid?*等价于id||name||country||rowid||rownum?
又
Select a.* ,count(b.*) from t1 a ,t2 b (where a.id=b.id(+));
出现错误:ORA01747: invalid user.table.column, table.column, orcolumnspecification
注释:user.table.column, table.column, orcolumn是一个列名的三种不同的写法。
Select count(b.*) from t2 b;
Select count(t2.*) from t2;
出现错误:ORA01747: invalid user.table.column, table.column, orcolumnspecification
注释:user.table.column, table.column, orcolumn是一个列名的三种不同的写法。
回答:
两处中的*含义不一样的,没有统一的一个意思:
在SQL语句中的*表示表的所有列,即假如表test有id、name和country三个列,则select * from test等于select id,name,countryfrom test,即*等于表示id,name,country(这个字符串在一条sql语句这种字符串中)
设计编程count(X)函数时,参数值*,表示统计表对应的段中所有的数据行(包括其上各列的值为空值null的数据行)。而设计编程count(X)函数时,将参数值A.B的形式规定为表A上的列B的意思,故count(X)函数中的参数值为b.*时,count(X)函数就将其解释为表b中的一列名为*的列,而实际上表b中不存在一列名为*的列,所以提示ORA-01747: 指定的列名无效(invalid user.table.column, table.column, orcolumn specification)。这是设计函数时没考虑b.*的形式而造成的结果。
附加:
关于null的说明以及和0的区别
一个变量(例如,表上的各个列其实本质就是一个个变量)的值为null(即数据(值)为空),表示该变量没有被赋予任何数值。换句话说,当一个变量的值为null时,表示该变量还不知道自己的值为多少,它的值可能是任一数值中的一个。所以说,一个变量的值为null,不等价于一个变量的值为0。一个变量的值为null,不等于说,就不用占用存储空间来存放null这个变量赋值中的一种状态。例如,表test1上有一个数据行,其上的各列的值皆为null:
insert into test1 values(null,null,null);//这里的null是个关键字,不是insert into test1 values(‘null’,‘null’,‘null’),这个是插入一行各列的值是字符串值为null这些字符的数据行。
则不是说该表对应的段上的数据块里不用消耗一定存储空间来存储该行的数据的,而还要的,即占据了一数据行的存储空间,只是存储的值不为什么数值,为空值。
附加2:
当表t2里不含有数据行即0条数据行时,count(*)的返回值为0;
当表t3里有2行数据如下:
id1 id2
---- -----
null 2
null 2
则select count(id1) from t3 where id2=2里count(id1)的返回值为0。
参考:
关于null的说明以及和0的区别
Oracle query - how to make count to return values with 0