Как включить результаты «ноль» / «0» в совокупное количество COUNT?

112

Я только что немного застрял с некоторым SQL. Я не думаю, что смогу блестяще сформулировать вопрос, поэтому позвольте мне показать вам.

У меня есть две таблицы, одна вызывается, другая назначается на прием. Я пытаюсь вернуть количество назначенных человеку встреч (в том числе, если их ноль). Назначение содержит person_idи существует индивидуальная запись person_id. Так COUNT(person_id)что это разумный подход.

Запрос:

SELECT person_id, COUNT(person_id) AS "number_of_appointments" 
FROM appointment 
GROUP BY person_id;

Вернет правильно, количество встреч, которые есть у person_id. Однако человек, у которого 0 встреч, не возвращается (очевидно, поскольку их нет в этой таблице).

Настройка оператора для взятия person_id из таблицы person дает мне что-то вроде:

SELECT person.person_id, COUNT(appointment.person_id) AS "number_of_appointments"
FROM appointment
JOIN person ON person.person_id = appointment.person_id
GROUP BY person.person_id;

Однако это по-прежнему будет возвращать только person_id, у которого есть встреча, а не то, что я хочу, что является возвращением с людьми, у которых нет встреч!

Есть предложения, пожалуйста?

КоричневыйE
источник
1
Что, если я хочу получить ноль | 0 как результат на одной таблице. У меня есть таблица vm_tool_licenses и запрос, как показано ниже, выберите vm_tool_id, count (vm_tool_license_active) из группы vm_tool_licenses от vm_tool_license_active, vm_tool_id, имеющий vm_tool_license_active = false`
Нарендра

Ответы:

101

Для этого вам нужно внешнее соединение (и вам нужно использовать person как "управляющую" таблицу)

SELECT person.person_id, COUNT(appointment.person_id) AS "number_of_appointments"
FROM person 
  LEFT JOIN appointment ON person.person_id = appointment.person_id
GROUP BY person.person_id;

Причина, по которой это работает, заключается в том, что внешнее (левое) соединение вернется NULLдля тех людей, у которых нет встречи. Агрегатная функция count()не будет считать NULLзначения, поэтому вы получите ноль.

Если вы хотите узнать больше о внешних соединениях, вот хороший учебник: http://sqlzoo.net/wiki/Using_Null

a_horse_with_no_name
источник
но что, если некоторые поля встречи НЕ ПУСТО (в определении таблицы)?
Лиор Ехезкели,
@LiorYehezkely: «некоторые столбцы» не имеют значения. Count () использует столбец соединения. Если это не ноль, то есть встреча, которую следует засчитать
a_horse_with_no_name
21

Вы должны использовать LEFT JOINвместоINNER JOIN

SELECT person.person_id, COUNT(appointment.person_id) AS "number_of_appointments"
FROM person 
LEFT JOIN appointment ON person.person_id = appointment.person_id
GROUP BY person.person_id;
Гамлет Акопян
источник
1
GROUP BY кажется опечаткой в ​​исходном вопросе, поскольку таблица не включена в запрос.
Йоахим Исакссон
7

если вы выполните внешнее соединение (с подсчетом), а затем используете этот результат в качестве подтаблицы, вы можете получить 0, как ожидалось (благодаря функции nvl)

Пример:

select P.person_id, nvl(A.nb_apptmts, 0) from 
(SELECT person.person_id
FROM person) P
LEFT JOIN 
(select person_id, count(*) as nb_apptmts
from appointment 
group by person_id) A
ON P.person_id = A.person_id
Франсуа Мазе
источник
5

ИСПОЛЬЗУЙТЕ соединение, чтобы получить нулевое количество в результате, используя GROUP BY.

просто 'join' выполняет внутреннее соединение в MS SQL, поэтому Go для левого или правого соединения.

Если таблица, содержащая первичный ключ, упоминается первой в запросе, используйте соединение LEFT, иначе соединение RIGHT.

НАПРИМЕР:

select WARDNO,count(WARDCODE) from MAIPADH 
right join  MSWARDH on MSWARDH.WARDNO= MAIPADH.WARDCODE
group by WARDNO

.

select WARDNO,count(WARDCODE) from MSWARDH
left join  MAIPADH on MSWARDH.WARDNO= MAIPADH.WARDCODE group by WARDNO

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

Рохини CG
источник
2

Чтобы еще меньше изменить исходный запрос, вы можете превратить свое соединение в RIGHTсоединение

SELECT person.person_id, COUNT(appointment.person_id) AS "number_of_appointments"
FROM appointment
RIGHT JOIN person ON person.person_id = appointment.person_id
GROUP BY person.person_id;

Это просто основывается на выбранном ответе, но поскольку внешнее соединение находится в RIGHTнаправлении, нужно добавить только одно слово и меньше изменений. - Просто помните, что он есть и иногда может сделать запросы более читабельными и потребовать меньше перестроения.

SFJ
источник
0

Проблема с LEFT JOIN заключается в том, что если нет встреч, он все равно будет возвращать одну строку с нулем, которая при агрегировании с помощью COUNT станет 1, и будет казаться, что у человека есть одна встреча, когда на самом деле у них ее нет. Думаю, это даст правильный результат:

SELECT person.person_id,
(SELECT COUNT(*) FROM appointment WHERE person.person_id = appointment.person_id) AS 'Appointments'
FROM person;
Дэннив
источник
Я просто собирался опубликовать то же самое решение, очень простое.
Иоиль