Wie werden "Null" / "0" -Ergebnisse in das COUNT-Aggregat aufgenommen?

112

Ich habe mich gerade ein bisschen mit SQL beschäftigt. Ich glaube nicht, dass ich die Frage brillant formulieren kann - also lass es mich dir zeigen.

Ich habe zwei Tische, einen namens Person, einen Termin. Ich versuche, die Anzahl der Termine einer Person zurückzugeben (auch wenn sie Null hat). Termin enthält die person_idund es gibt eine person_idpro Termin. So COUNT(person_id)ist ein vernünftiger Ansatz.

Die Abfrage:

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

Gibt die Anzahl der Termine, die eine person_id hat, korrekt zurück. Eine Person mit 0 Terminen wird jedoch nicht zurückgegeben (offensichtlich, da sie nicht in dieser Tabelle enthalten ist).

Wenn ich die Anweisung so ändere, dass person_id aus der Personentabelle entfernt wird, habe ich ungefähr Folgendes:

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;

Dies wird jedoch immer noch nur eine person_id zurückgeben, die einen Termin hat und nicht das, was ich will, was eine Rückgabe mit Personen ist, die 0 Termine haben!

Irgendwelche Vorschläge bitte?

BrownE
quelle
1
Was ist, wenn ich Null bekommen möchte? 0 als Ergebnis für eine einzelne Tabelle. Ich habe die Tabelle vm_tool_licenses und die Abfrage ist wie folgt: Wählen Sie vm_tool_id, count (vm_tool_license_active) aus der Gruppe vm_tool_licenses von vm_tool_license_active, vm_tool_id mit vm_tool_license_active = false`
Narendra

Antworten:

101

Sie möchten dafür eine äußere Verknüpfung (und Sie müssen die Person als "Fahr" -Tabelle verwenden).

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;

Der Grund, warum dies funktioniert, ist, dass der äußere (linke) Join NULLfür diejenigen Personen zurückkehrt, die keinen Termin haben. Die Aggregatfunktion zählt count()keine NULLWerte und daher erhalten Sie eine Null.

Wenn Sie mehr über äußere Verknüpfungen erfahren möchten, finden Sie hier ein nettes Tutorial: http://sqlzoo.net/wiki/Using_Null

ein Pferd ohne Name
quelle
aber was ist, wenn einige der Felder des Termins NICHT NULL sind (in der Tabellendefinition)?
Lior Yehezkely
@LiorYehezkely: "Einige der Spalten" spielen keine Rolle. Die count () verwendet die Join-Spalte. Wenn das nicht null ist, gibt es einen Termin, der gezählt werden sollte
a_horse_with_no_name
21

Sie müssen LEFT JOINanstelle von verwendenINNER 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;
Weiler Hakobyan
quelle
1
Die GROUP BY scheint ein Tippfehler in der ursprünglichen Frage zu sein, da die Tabelle nicht in der Abfrage enthalten ist.
Joachim Isaksson
7

Wenn Sie den äußeren Join (mit der Anzahl) ausführen und dieses Ergebnis dann als Untertabelle verwenden, können Sie wie erwartet 0 erhalten (dank der Funktion 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
Francois Mazet
quelle
5

Verwenden Sie join, um mit GROUP BY die Anzahl 0 im Ergebnis zu erhalten.

Durch einfaches 'Join' wird der innere Join in MS SQL ausgeführt. Wählen Sie also den linken oder rechten Join.

Wenn die Tabelle, die den Primärschlüssel enthält, zuerst in der Abfrage erwähnt wird, verwenden Sie LEFT join else RIGHT join.

Z.B:

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

Nehmen Sie die Gruppe von aus der Tabelle mit dem Primärschlüssel und zählen Sie aus der anderen Tabelle mit den tatsächlichen Einträgen / Details.

Rohini CG
quelle
2

Um Ihre ursprüngliche Abfrage noch weniger zu ändern, können Sie Ihren Join in einen RIGHTJoin verwandeln

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;

Dies baut nur auf der ausgewählten Antwort auf, aber da die äußere Verknüpfung in die RIGHTRichtung weist, muss nur ein Wort hinzugefügt und weniger geändert werden. - Denken Sie daran, dass es vorhanden ist und manchmal Abfragen lesbarer macht und weniger Neuerstellung erfordert.

sfj
quelle
0

Das Problem mit einem LEFT JOIN ist, dass, wenn keine Termine vorhanden sind, immer noch eine Zeile mit einer Null zurückgegeben wird, die, wenn sie von COUNT aggregiert wird, 1 wird, und es scheint, dass die Person einen Termin hat, wenn sie tatsächlich keinen hat. Ich denke, dies wird die richtigen Ergebnisse liefern:

SELECT person.person_id,
(SELECT COUNT(*) FROM appointment WHERE person.person_id = appointment.person_id) AS 'Appointments'
FROM person;
dannyw
quelle