Почему count не возвращает 0 в пустой таблице - PullRequest
4 голосов
/ 14 марта 2019

Мне нужно посчитать строки таблицы, но мне было предложено необычное поведение count (*).

count (*) не возвращает результаты, когда я использую выбор из нескольких столбцов в пустой таблице.Но возвращает ожидаемые результаты (0 строк), если я удаляю другие столбцы из оператора выбора (Выбор одного столбца).

В приведенном ниже коде вы найдете несколько тестов, чтобы показать вам, о чем я говорю.

Структура кода ниже:

1) Создание таблицы

2) Выбор нескольких столбцов в тестах пустой таблицы, который возвращает неожиданный результатрезультаты

3) Выбор одного столбца в тесте пустой таблицы, который возвращает ожидаемый результат

4) Выбор нескольких столбцов в тесте заполненной таблицы, который возвращает ожидаемый результат

Вопрос

Учитывая эти результаты, мой вопрос:

Почему выбор из нескольких столбцов в пустой таблице не возвращает 0, а выбор из одного столбца возвращает его?

Определение ожидаемых результатов

Ожидаемые результаты для меня означают:

, если таблица пуста, count (*) возвращает 0.

Если таблица не пустая count возвращает количество строк

- CREATE TEST TABLE

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 ]

4 голосов
/ 14 марта 2019

Итак, я прочитал о механизмах группировки sybase и пришел к выводу, что в вашем запросе у вас есть «расширенный столбец Transact-SQL» (см. документы по группе в разделе Использование - > Расширения Transact-SQL для группировки и наличия):

Список выбора, включающий агрегаты, может включать в себя расширенные столбцы, которые не являются аргументами агрегатных функций и не включены в группу по пункту . Расширенный столбец влияет на отображение окончательных результатов, поскольку отображаются дополнительные строки. * (выделено мной)

(относительно *: это последнее утверждение на самом деле неверно в вашем конкретном случае, поскольку одна строка превращается в ноль)

также в документах по группе по в разделе Использование -> Как работает группировка и наличие запросов с агрегатами:

Предложение group by собирает оставшиеся строки в одну группу для каждого уникального значения в группе по выражению. Пропуск группы создает единую группу для всей таблицы. (выделено мной)

Так по сути:

  1. с COUNT(*) приведет к тому, что весь запрос будет агрегатным, так как это агрегатная функция (вызывающая неявную GROUP BY NULL)
  2. добавление идентификатора в предложении SELECT расширит первую группу (состоящую из строк) на содержащиеся в ней строки (нет) и объединит ее вместе со столбцами совокупного результата.

в вашем случае: счетчик равен 0, так как вы также запрашиваете идентификатор, для каждого идентификатора будет сгенерирована строка, к которой добавляется счетчик. однако, поскольку в вашей таблице нет строк, нет никаких строк результата, следовательно, нет присваиваний. (Некоторые примеры приведены в связанных документах, и, поскольку идентификатор отсутствует, а существующий идентификатор должен быть в столбце идентификатора вашего результата, ...)

чтобы всегда получать счетчик, вам, вероятно, нужно только SELECT @ROWS = COUNT(*) и выбирать идентификаторы отдельно.

0 голосов
/ 14 марта 2019

Этот запрос:

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

Проблема в том, что COUNT(*) делает этот запрос агрегации, но вы также хотите вернуть ID. Нет GROUP BY.

Я подозреваю, что ваша главная проблема в том, что вы игнорируете такие ошибки.

Этот SQL Fiddle использует SQL Server (который похож на Sybase). Однако ошибка носит довольно общий характер и связана с запросом, который не будет работать практически в любой базе данных.

0 голосов
/ 14 марта 2019

Если вы подсчитываете строки и пытаетесь получить идентификатор, когда строк нет - вам нужно проверить, СУЩЕСТВУЕТ ли они. Примерно так:

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 строки вы получите ошибку подзапроса.

...