为什么 count 在空表上不返回 0

Nel*_*sen 5 sql sybase sap-ase

我需要计算表的行数,但我收到了 count(*) 异常行为的提示。

当我在空表上使用多列选择时,count(*) 不返回结果。但如果我从 select 语句(单列选择)中删除其他列,则会返回预期结果(0 行)。

在下面的代码中,您将找到多个测试来向您展示我在说什么。

下面代码的结构是:

1)创建表

2)空表测试上的多列选择,返回意外结果

3)空表测试单列select,返回预期结果

4)填充表测试上的多列选择,返回预期结果

问题

鉴于这个结果我的问题是:

为什么空表上的多列选择不返回0,而单列选择返回0?

预期结果定义

对我来说预期结果意味着:

如果表为空,count(*) 返回 0。

如果表不为空,则返回行数

--创建测试表

CREATE TABLE #EMPTY_TABLE(
    ID INT
)

DECLARE @ID INT
DECLARE @ROWS INT
Run Code Online (Sandbox Code Playgroud)

--空表多列选择

--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
Run Code Online (Sandbox Code Playgroud)

--空表的单列选择

--assignment attempt (Single-column SELECT)
SELECT @ROWS = COUNT(*)
FROM #EMPTY_TABLE

--returns 0 the expected result
SELECT @ROWS Test_03
Run Code Online (Sandbox Code Playgroud)

--带有填充表的多列选择

--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
Run Code Online (Sandbox Code Playgroud)

Jak*_*umi 4

因此,我阅读了 sybase 的分组机制,并得出结论,在您的查询中,您有一个“Transact-SQL 扩展列”(请参阅​​:使用情况下的group by 文档-> Transact-SQL 扩展来分组依据和具有):

包含聚合的选择列表可以包含不是聚合函数参数且不包含在 group by 子句中的扩展列。扩展列会影响最终结果的显示,因为会显示额外的行。* (强调我的)

(关于 *:在您的具体情况下,最后一个语句实际上是错误的,因为一行变成零行)

同样在group by 的文档中,在用法 -> 如何进行分组以及使用聚合进行查询时,您会发现:

对于 group by 表达式中的每个唯一值,group by 子句将剩余行收集到一组中。省略 group by 会为整个表创建一个组。 (强调我的)

所以本质上是:

  1. 拥有 aCOUNT(*)将触发整个查询成为聚合,因为它是聚合函数(导致隐式GROUP BY NULL
  2. 在子句中添加 ID SELECT,然后会将第一组(不包含行)扩展到其包含的行(无),并将其与聚合结果列连接在一起。

在您的情况下:计数为 0,因为您还查询了 id,因此对于每个 id 都会生成一行,并在其中附加计数。但是,由于您的表没有行,因此没有任何结果行,因此没有分配。(一些示例位于链接的文档中,并且由于没有 id 并且现有 id 必须位于结果的 id 列中,...)

为了始终获得计数,您可能应该只SELECT @ROWS = COUNT(*)单独选择 id。