关于使用count(X) 函数的说明(附加:关于null的说明以及和0的区别)

关于使用count(X) 函数的说明

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

1            tone            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的数据行

注释:COUNT(column)的一般形式为COUNT(column1||column2||......)。


参见:

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







### 回答1: 以下是求带附加头结点的单链表长度的函数实现: ```c int Length(NODE *head) { int len = 0; NODE *p = head->next; // 第一个节点 while (p != NULL) { len++; p = p->next; } return len; } ``` 附加头结点是单链表中的一个哑节点,它的作用是方便对单链表的操作。在这个函数中,我们从头结点的下一个节点开始遍历单链表,每遍历一个节点就将计数器加一,直到遍历到链表末尾。最后返回计数器的值就是单链表的长度。 ### 回答2: 要编写一个函数来求带附加头结点的单链表的长度,函数原型为 int Length(NODE *head)。其中,参数 head 为单链表的头指针;函数值为单链表的长度。 实现这个函数的思路是遍历链表,直到遇到头结点,遍历过程中累计结点的数量即为链表的长度。 具体的实现如下: 1. 定义一个变量 count,并初始化为0,用于记录链表的长度。 2. 判断头结点是否为空,如果为空,则链表的长度为0,直接返回count。 3. 定义一个指针 p,并初始化为头结点的下一个结点。 4. 使用循环遍历链表,直到遇到头结点为止。 1. 每次遍历时,将 count 增加1。 2. 将 p 指针指向下一个结点。 5. 循环结束后,返回 count。 以下是具体的函数实现代码: ```C++ int Length(NODE *head) { int count = 0; if (head == nullptr) { return count; } NODE *p = head->next; while (p != head) { count++; p = p->next; } return count; } ``` 注意:这个函数是针对带附加头结点的单链表的长度进行求解的。如果是普通的单链表,没有附加头结点,需要做相应的修改。 ### 回答3: 编写一个函数来求解带附加头结点的单链表的长度。该函数使用迭代的方式遍历链表,统计节点的数量,并返回该数量。 ```c #include <stdio.h> // 定义链表节点结构体 typedef struct Node{ int data; struct Node *next; }NODE; // 求带附加头结点的单链表的长度 int Length(NODE *head){ int count = 0; // 计数器 // 遍历链表,统计节点数量 NODE *cur = head->next; // 从头节点的下一个节点开始遍历 while(cur != NULL){ count++; // 计数器加一 cur = cur->next; // 移动到下一个节点 } return count; // 返回节点数量 } int main(){ // 创建带附加头结点的单链表 NODE *head = (NODE*)malloc(sizeof(NODE)); head->next = NULL; // 空链表 // 创建节点 NODE *node1 = (NODE*)malloc(sizeof(NODE)); node1->data = 1; node1->next = NULL; head->next = node1; // 将节点1连接到头结点之后 NODE *node2 = (NODE*)malloc(sizeof(NODE)); node2->data = 2; node2->next = NULL; node1->next = node2; // 将节点2连接到节点1之后 NODE *node3 = (NODE*)malloc(sizeof(NODE)); node3->data = 3; node3->next = NULL; node2->next = node3; // 将节点3连接到节点2之后 // 调用函数求解链表的长度 int length = Length(head); printf("链表的长度为:%d\n", length); // 释放内存 free(node3); free(node2); free(node1); free(head); return 0; } ``` 以上程序会输出链表的长度为3。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值