Как вернуть значение count(*) равное 0 вместо NULL

#sql #sql-server #tsql #aggregate-functions

#sql #sql-сервер #tsql #агрегатные функции

Вопрос:

У меня есть этот фрагмент кода:

 SELECT Project, Financial_Year, COUNT(*) AS HighRiskCount
INTO #HighRisk 
FROM #TempRisk1
WHERE Risk_1 = 3
GROUP BY Project, Financial_Year
  

где он не возвращает никаких строк, когда значение count равно нулю. Как мне сделать так, чтобы эти строки отображались с значением HighRiskCount равным 0?

Комментарии:

1. Можете ли вы подтвердить, что данные существуют с Risk_1 = 3, но с нулевым значением?

2. Как могут существовать данные, когда значение count равно нулю …?

Ответ №1:

Вы не можете выбрать значения из таблицы, когда количество строк равно 0. Где он получит значения для несуществующих строк?

Для этого вам понадобится другая таблица, которая определяет ваш список допустимых Project и Financial_Year значений. Затем вы выберете из этой таблицы, выполните left join в существующей таблице, затем выполните группировку.

Что-то вроде этого:

 SELECT l.Project, l.Financial_Year, COUNT(t.Project) AS HighRiskCount
INTO #HighRisk 
FROM MasterRiskList l
left join #TempRisk1 t on t.Project = l.Project and t.Financial_Year = l.Financial_Year
WHERE t.Risk_1 = 3
GROUP BY l.Project, l.Financial_Year
  

Комментарии:

1. Ключевой момент. Все остальные ответы пока пропускают это. Какие значения будут помещены в Project и Financial_Year для строк, когда значение count равно нулю?

2. Он выбирает проект и финансовый год из основного списка, поэтому он будет отображать их, когда количество равно нулю, я думаю.

3. @JamesJiao: MasterRiskList Это то, что я добавил в свой запрос в качестве примера; этого нет в запросе OP.

4. Я знаю .. на что я ссылался.

5. @JamieF Я этого не пропустил, это не входило в сферу вопроса. Я фактически обработал это для всех строк, содержащих любую комбинацию project и financial_year

Ответ №2:

Оберните свой SELECT запрос в ISNULL :

 SELECT ISNULL((SELECT Project, Financial_Year, COUNT(*) AS hrc
INTO #HighRisk 
FROM #TempRisk1
WHERE Risk_1 = 3
GROUP BY Project, Financial_Year),0) AS HighRiskCount
  

Если ваш SELECT возвращает число, оно пройдет. Если оно вернет значение NULL , 0 оно пройдет.

Комментарии:

1. -1 этот синтаксис недопустим. В списке выбора может быть указано только одно выражение, когда подзапрос не вводится с помощью EXISTS.

2. Синтаксис НЕ является неправильным! Это может работать не в каждой ситуации, в зависимости от того, что вы ищете, но для этой ситуации это работает идеально. Я часто его использую.

3. сообщение об ошибке было скопировано из studio management. Я только что добавил первое предложение. Кроме того, это не единственная проблема с вашим ответом. Вы выбираете столбцы во временную таблицу внутри подзапроса. Ваш ответ не подлежит восстановлению

4. Тогда почему это так хорошо работает для меня?

5. Я предполагаю, что в другом примере вы каким-то образом приступили к работе, вы выбираете только 1 столбец внутри подзапроса и не пытаетесь создать новую временную таблицу внутри подзапроса. Если эти условия выполнены, ошибка не будет возвращена, если подзапрос возвращает 0 или 1 строку

Ответ №3:

Предполагая, что у вас есть ‘Project’ и ‘Financial_Year’, где Risk_1 отличается от 3, и это те, которые вы собираетесь включить.

 SELECT Project, Financial_Year, SUM(CASE WHEN RISK_1 = 3 THEN 1 ELSE 0 END) AS HighRiskCount
INTO #HighRisk 
FROM #TempRisk1
GROUP BY Project, Financial_Year
  

Обратите внимание, что я удалил часть where.

Кстати, ваш текущий запрос не возвращает null, он не возвращает строк.

Комментарии:

1. Это то, что я искал. Работает как шарм.

2. если комбинация (project, financial_year), например (‘liquidate’, 2007), вообще не имеет строки в таблице, ваш запрос не вернет ни одной строки. СУММА просто заменила значение COUNT, не предоставляя других преимуществ. Как сказано в топе проголосовавших, мы должны начать с действительного (обязательного) списка.

3. @oldpride это верно, но если нет данных за весь год, действительно ли мы хотим включать какие-либо строки за этот год — это был бы скользкий путь. Кроме того, это, похоже, не вопрос

Ответ №4:

Использовать:

    SELECT x.Project, x.financial_Year, 
          COUNT(y.*) AS HighRiskCount
     INTO #HighRisk 
     FROM (SELECT DISTINCT t.project, t.financial_year
             FROM #TempRisk1
            WHERE t.Risk_1 = 3) x
LEFT JOIN #TempRisk1 y ON y.project = x.project
                      AND y.financial_year = x.financial_year
 GROUP BY x.Project, x.Financial_Year
  

Единственный способ получить нулевые значения — использовать OUTER объединение со списком различных значений, для которых вы хотите видеть нулевые значения.

Ответ №5:

В SQL обычно возникает проблема с возвратом значений, которых нет в таблице. Для выполнения этого (в любом случае, без хранимой процедуры) вам понадобится другая таблица, содержащая недостающие значения.

Предполагая, что вам нужна одна строка на комбинацию project / financial year, вам понадобится таблица, содержащая каждую допустимую комбинацию Project, Finanical_Year:

  SELECT HR.Project, HR.Financial_Year, COUNT(HR.Risk_1) AS HighRiskCount
 INTO #HighRisk HR RIGHT OUTER JOIN ProjectYears PY
   ON HR.Project = PY.Project AND HR.Financial_Year = PY.Financial_Year
 FROM #TempRisk1
 WHERE Risk_1 = 3
 GROUP BY HR.Project, HR.Financial_Year
  

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

В качестве альтернативы, вы можете возвращать только одну запись 0 count для каждого проекта (или, возможно, одну для financial_year). Вы бы изменили вышеупомянутое решение так, чтобы объединенная таблица содержала только этот один столбец.

Ответ №6:

Немного дольше, но как насчет этого в качестве решения?

 IF EXISTS (
        SELECT *
        FROM #TempRisk1
        WHERE Risk_1 = 3
    )
    BEGIN
        SELECT Project, Financial_Year, COUNT(*) AS HighRiskCount
        INTO #HighRisk 
        FROM #TempRisk1
        WHERE Risk_1 = 3
        GROUP BY Project, Financial_Year
    END
ELSE
    BEGIN
        INSERT INTO #HighRisk 
            SELECT 'Project', 'Financial_Year', 0
    END
  

Ответ №7:

MSDN — функция ISNULL

 
SELECT Project, Financial_Year, ISNULL(COUNT(*), 0) AS HighRiskCount
INTO #HighRisk 
FROM #TempRisk1
WHERE Risk_1 = 3
GROUP BY Project, Financial_Year
  

Комментарии:

1. Как и в случае с другим подобным ответом, это не сработает. Где он будет получать значения для Project и Financial_Year , если строк там нет, чтобы их предоставить?

2. Вы правы, я понял это примерно через 3 секунды после публикации. В такие моменты я хотел бы, чтобы был способ удалить SO, но я полагаю, что в следующий раз я потрачу дополнительные 3 секунды, чтобы подумать, прежде чем отправлять… к вам приходит одобрение…