Comment inclure des résultats «zéro» / «0» dans COUNT agrégat?

112

Je suis juste un peu coincé avec du SQL. Je ne pense pas que je puisse formuler la question avec brio - alors laissez-moi vous montrer.

J'ai deux tables, une appelée personne, une appelée rendez-vous. J'essaie de renvoyer le nombre de rendez-vous qu'une personne a (y compris si elle en a zéro). Le rendez-vous contient le person_idet il y en a un person_idpar rendez-vous. Il en COUNT(person_id)va de même pour une approche sensée.

La requête:

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

Renvoie correctement, le nombre de rendez-vous d'un person_id. Cependant, une personne qui n'a pas de rendez-vous n'est pas renvoyée (évidemment car elle ne figure pas dans ce tableau).

Ajuster l'instruction pour prendre person_id de la table person me donne quelque chose comme:

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;

Cependant, cela ne renverra toujours qu'un person_id qui a un rendez-vous et non ce que je veux qui est un retour avec des personnes qui ont 0 rendez-vous!

Des suggestions s'il vous plaît?

MarronE
la source
1
Et si je veux obtenir zéro | 0 comme résultat sur une seule table. J'ai la table vm_tool_licenses et la requête est comme ci-dessous, sélectionnez vm_tool_id, count (vm_tool_license_active) du groupe vm_tool_licenses par vm_tool_license_active, vm_tool_id ayant vm_tool_license_active = false`
Narendra

Réponses:

101

Vous voulez une jointure externe pour cela (et vous devez utiliser la personne comme table de "conduite")

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;

La raison pour laquelle cela fonctionne, c'est que la jointure externe (gauche) reviendra NULLpour les personnes qui n'ont pas de rendez-vous. La fonction d'agrégation count()ne comptera pas les NULLvaleurs et vous obtiendrez ainsi un zéro.

Si vous voulez en savoir plus sur les jointures externes, voici un joli tutoriel: http://sqlzoo.net/wiki/Using_Null

un cheval sans nom
la source
mais que faire si certains des champs du rendez-vous ne sont PAS NULL (dans la définition de table)?
Lior Yehezkely le
@LiorYehezkely: "certaines des colonnes" n'a pas d'importance. Le count () utilise la colonne de jointure. Si ce n'est pas nul, alors il y a un rendez-vous qui devrait être compté
a_horse_with_no_name
21

Vous devez utiliser à la LEFT JOINplace deINNER 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;
Hameau Hakobyan
la source
1
Le GROUP BY semble être une faute de frappe dans la question d'origine car la table n'est pas incluse dans la requête.
Joachim Isaksson
7

si vous faites la jointure externe (avec le nombre), puis utilisez ce résultat comme sous-table, vous pouvez obtenir 0 comme prévu (grâce à la fonction nvl)

Ex:

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
François Mazet
la source
5

Utilisez la jointure pour obtenir 0 compte dans le résultat en utilisant GROUP BY.

il suffit de «rejoindre» pour faire une jointure interne dans MS SQL, donc, optez pour une jointure gauche ou droite.

Si la table qui contient la clé primaire est mentionnée en premier dans la requête, utilisez la jointure GAUCHE sinon la jointure DROITE.

PAR EXEMPLE:

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

Prenez group by de la table qui a la clé primaire et comptez à partir de l'autre table qui a des entrées / détails réels.

Rohini CG
la source
2

Pour modifier encore moins votre requête d'origine, vous pouvez transformer votre jointure en RIGHTjointure

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;

Cela se base uniquement sur la réponse sélectionnée, mais comme la jointure externe est dans la RIGHTdirection, un seul mot doit être ajouté et moins de changements. - N'oubliez pas qu'il est là et peut parfois rendre les requêtes plus lisibles et nécessiter moins de reconstruction.

sfj
la source
0

Le problème avec une jointure à gauche est que s'il n'y a pas de rendez-vous, il renverra toujours une ligne avec un null, qui, une fois agrégée par COUNT, deviendra 1, et il apparaîtra que la personne a un rendez-vous alors qu'elle n'en a pas. Je pense que cela donnera les bons résultats:

SELECT person.person_id,
(SELECT COUNT(*) FROM appointment WHERE person.person_id = appointment.person_id) AS 'Appointments'
FROM person;
dannyw
la source
J'allais juste poster cette même solution, très simple.
Joel