#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:
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 секунды, чтобы подумать, прежде чем отправлять… к вам приходит одобрение…