为什么计数不 return 0 为空 table
Why count doesn't return 0 on empty table
我需要计算 table 的行数,但系统提示我出现异常的 count(*) 行为。
当我在空 table 上使用多列 select 时,count(*) 不会 return 结果。但是如果我从 select 语句中删除其他列(单列 Select),return 的预期结果(0 行)。
在下面的代码中,您会发现多个测试向您展示了我在说什么。
下面代码的结构是:
1) 创建 table
2) 多列 select 空 table 测试,return 意外结果
3) 单列 select 空 table 测试,return 是预期结果
4) 多列 select 填充 table 测试,return 是预期结果
问题
鉴于此结果,我的问题是:
为什么空 table 上的多列 select 不是 return 0,而单列 select return 呢?
预期结果定义
我的预期结果是指:
如果一个table为空,count(*)returns 0。
如果 table 不为空,则计数 return 行数
--创建测试TABLE
CREATE TABLE #EMPTY_TABLE(
ID INT
)
DECLARE @ID INT
DECLARE @ROWS INT
--多列 SELECT 带空 TABLE
--assignment attempt (Multi-column SELECT)
SELECT @ID = ID, @ROWS = COUNT(*)
FROM #EMPTY_TABLE
--return Null instead of 0
SELECT @ROWS Test_01 , ISNULL(@ROWS, 1 )'IS NULL'
--Set variable with random value, just to show that not even the assignment is happening
SET @ROWS = 29
--assignment attempt (Multi-column SELECT)
SELECT @ID = ID, @ROWS = COUNT(*)
FROM #EMPTY_TABLE
--return 29 instead of 0
SELECT @ROWS Test_02
--单列 SELECT 带空 TABLE
--assignment attempt (Single-column SELECT)
SELECT @ROWS = COUNT(*)
FROM #EMPTY_TABLE
--returns 0 the expected result
SELECT @ROWS Test_03
--多列 SELECT 带填充 TABLE
--insert a row
INSERT INTO #EMPTY_TABLE(ID)
SELECT 1
--assignment attempt
SELECT @ID = ID, @ROWS = COUNT(*)
FROM #EMPTY_TABLE
--Returns 1
SELECT @ROWS Test_04
所以我阅读了 sybase 的分组机制,并得出结论,在您的查询中您有一个 "Transact-SQL extended column"(请参阅:docs on group by under Usage -> Transact-SQL 分组依据和具有的扩展):
A select list that includes aggregates can include extended columns that are not arguments of aggregate functions and are not included in the group by clause. An extended column affects the display of final results, since additional rows are displayed.* (emphasis mine)
(关于 *:在您的特定情况下,最后一条语句实际上是错误的,因为一行变成零行)
同样在 docs on group by 下的使用 -> 如何分组并使用聚合进行查询你会发现:
The group by clause collects the remaining rows into one group for each unique value in the group by expression. Omitting group by creates a single group for the whole table. (emphasis mine)
所以基本上:
- 有一个
COUNT(*)
将触发整个查询成为一个聚合,因为它是一个聚合函数(导致隐式 GROUP BY NULL
)
- 在
SELECT
子句中添加 ID,然后会将第一组(不包含任何行)扩展到其包含的行 (none) 并将其与聚合结果列连接在一起。
在您的情况下:计数为 0,因为您还查询了 ID,对于每个 ID 都会生成一行,计数将附加到该行。但是,由于您的 table 没有行,因此没有任何结果行,因此没有分配。 (一些示例在链接文档中,并且由于没有 id 并且现有 id 必须在结果的 id 列中,...)
要始终获得计数,您可能应该只分别使用 SELECT @ROWS = COUNT(*)
和 select 个 ID。
如果您正在计算行数并在没有行时尝试获取 ID - 您需要检查它们是否存在。
像这样:
SELECT COUNT(*),
(CASE WHEN EXISTS(SELECT ID FROM EMPTY_TABLE) THEN (SELECT ID FROM EMPTY_TABLE) ELSE 0 END) AS n_id
FROM EMPTY_TABLE
如果超过 1 行,您将收到子查询错误。
这个查询:
SELECT @ID = ID, @ROWS = COUNT(*)
FROM #EMPTY_TABLE
问题是 COUNT(*)
使它成为聚合查询,但您还想 return ID
。没有GROUP BY
.
我怀疑你的最终问题是你忽略了这些错误。
This SQL Fiddle 使用 SQL 服务器(类似于 Sybase)。然而,失败是非常普遍的,并且由于查询在几乎所有数据库中都不起作用。
我需要计算 table 的行数,但系统提示我出现异常的 count(*) 行为。
当我在空 table 上使用多列 select 时,count(*) 不会 return 结果。但是如果我从 select 语句中删除其他列(单列 Select),return 的预期结果(0 行)。
在下面的代码中,您会发现多个测试向您展示了我在说什么。
下面代码的结构是:
1) 创建 table
2) 多列 select 空 table 测试,return 意外结果
3) 单列 select 空 table 测试,return 是预期结果
4) 多列 select 填充 table 测试,return 是预期结果
问题
鉴于此结果,我的问题是:
为什么空 table 上的多列 select 不是 return 0,而单列 select return 呢?
预期结果定义
我的预期结果是指:
如果一个table为空,count(*)returns 0。
如果 table 不为空,则计数 return 行数
--创建测试TABLE
CREATE TABLE #EMPTY_TABLE(
ID INT
)
DECLARE @ID INT
DECLARE @ROWS INT
--多列 SELECT 带空 TABLE
--assignment attempt (Multi-column SELECT)
SELECT @ID = ID, @ROWS = COUNT(*)
FROM #EMPTY_TABLE
--return Null instead of 0
SELECT @ROWS Test_01 , ISNULL(@ROWS, 1 )'IS NULL'
--Set variable with random value, just to show that not even the assignment is happening
SET @ROWS = 29
--assignment attempt (Multi-column SELECT)
SELECT @ID = ID, @ROWS = COUNT(*)
FROM #EMPTY_TABLE
--return 29 instead of 0
SELECT @ROWS Test_02
--单列 SELECT 带空 TABLE
--assignment attempt (Single-column SELECT)
SELECT @ROWS = COUNT(*)
FROM #EMPTY_TABLE
--returns 0 the expected result
SELECT @ROWS Test_03
--多列 SELECT 带填充 TABLE
--insert a row
INSERT INTO #EMPTY_TABLE(ID)
SELECT 1
--assignment attempt
SELECT @ID = ID, @ROWS = COUNT(*)
FROM #EMPTY_TABLE
--Returns 1
SELECT @ROWS Test_04
所以我阅读了 sybase 的分组机制,并得出结论,在您的查询中您有一个 "Transact-SQL extended column"(请参阅:docs on group by under Usage -> Transact-SQL 分组依据和具有的扩展):
A select list that includes aggregates can include extended columns that are not arguments of aggregate functions and are not included in the group by clause. An extended column affects the display of final results, since additional rows are displayed.* (emphasis mine)
(关于 *:在您的特定情况下,最后一条语句实际上是错误的,因为一行变成零行)
同样在 docs on group by 下的使用 -> 如何分组并使用聚合进行查询你会发现:
The group by clause collects the remaining rows into one group for each unique value in the group by expression. Omitting group by creates a single group for the whole table. (emphasis mine)
所以基本上:
- 有一个
COUNT(*)
将触发整个查询成为一个聚合,因为它是一个聚合函数(导致隐式GROUP BY NULL
) - 在
SELECT
子句中添加 ID,然后会将第一组(不包含任何行)扩展到其包含的行 (none) 并将其与聚合结果列连接在一起。
在您的情况下:计数为 0,因为您还查询了 ID,对于每个 ID 都会生成一行,计数将附加到该行。但是,由于您的 table 没有行,因此没有任何结果行,因此没有分配。 (一些示例在链接文档中,并且由于没有 id 并且现有 id 必须在结果的 id 列中,...)
要始终获得计数,您可能应该只分别使用 SELECT @ROWS = COUNT(*)
和 select 个 ID。
如果您正在计算行数并在没有行时尝试获取 ID - 您需要检查它们是否存在。 像这样:
SELECT COUNT(*),
(CASE WHEN EXISTS(SELECT ID FROM EMPTY_TABLE) THEN (SELECT ID FROM EMPTY_TABLE) ELSE 0 END) AS n_id
FROM EMPTY_TABLE
如果超过 1 行,您将收到子查询错误。
这个查询:
SELECT @ID = ID, @ROWS = COUNT(*)
FROM #EMPTY_TABLE
问题是 COUNT(*)
使它成为聚合查询,但您还想 return ID
。没有GROUP BY
.
我怀疑你的最终问题是你忽略了这些错误。
This SQL Fiddle 使用 SQL 服务器(类似于 Sybase)。然而,失败是非常普遍的,并且由于查询在几乎所有数据库中都不起作用。