为什么计数在空表上不返回0

时间:2019-03-14 09:37:11

标签: sql sybase sybase-ase

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

当我在空表上使用多列选择时,

count(*)不返回结果。但是,如果我从select语句(单列Select)中删除其他列,则会返回预期结果(0行)。

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

以下代码的结构为:

1)创建表格

2)在空表测试中选择多列,这将返回意外结果

3)在空表测试中选择单列,这将返回预期结果

4)在填充表测试中选择多列,它返回预期结果

问题

鉴于此结果,我的问题是:

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

预期结果定义

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

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

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

-创建测试表

CREATE TABLE #EMPTY_TABLE(
    ID INT
)

DECLARE @ID INT
DECLARE @ROWS INT

-带空表的多列选择

--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

-带空表的单列选择

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

--returns 0 the expected result
SELECT @ROWS Test_03

-带填充表的多列选择

--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

3 个答案:

答案 0 :(得分:4)

因此,我阅读了sybase的分组机制,并得出结论,在您的查询中,您具有“ Transact-SQL扩展列”(请参见:用法-> Transact-SQL扩展下的docs on group by以分组并具有):

  

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

(关于*:这最后一条语句在您的特定情况下实际上是错误的,因为一行变成了零行)

还可以在docs on group by的“用法”->“如何按分组进行汇总以及如何查询聚合”中找到

  

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

从本质上说:

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

在您的情况下:计数为0,因为您还要查询id,所以对于每个id,都会生成一行,该计数将附加到该行。但是,由于表没有行,因此没有结果行,因此也没有赋值。 (某些示例在链接的文档中,并且由于没有ID,并且现有ID必须在结果的ID列中,...)

要始终获取计数,您可能应该只SELECT @ROWS = COUNT(*)并分别选择ID。

答案 1 :(得分:0)

如果要统计行数并尝试在没有行的情况下获取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,则会出现子查询错误。

答案 2 :(得分:0)

此查询:

SELECT @ID = ID, @ROWS = COUNT(*) 
FROM #EMPTY_TABLE

问题是COUNT(*)使其成为聚合查询,但是您还想返回ID。没有GROUP BY

我怀疑您的最终问题是您忽略了此类错误。

This SQL Fiddle使用SQL Server(与Sybase类似)。但是,失败是非常普遍的,并且是由于查询在几乎所有数据库中均不起作用。