Come includere "zero" / "0" risultati in COUNT aggregato?


112

Mi sono solo un po 'bloccato con un po' di SQL. Non credo di poter formulare la domanda in modo brillante, quindi lascia che te lo mostri.

Ho due tavoli, uno chiamato persona, uno chiamato appuntamento. Sto cercando di restituire il numero di appuntamenti di una persona (incluso se hanno zero). L'appuntamento contiene il person_ide c'è un person_idper appuntamento. Quindi COUNT(person_id)è un approccio ragionevole.

La domanda:

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

Restituirà correttamente il numero di appuntamenti di un person_id. Tuttavia, una persona che ha 0 appuntamenti non viene restituita (ovviamente in quanto non sono in quella tabella).

Modificare l'istruzione per prendere person_id dalla tabella person mi dà qualcosa del tipo:

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;

Questo tuttavia, restituirà comunque solo un person_id che ha un appuntamento e non quello che voglio che è un ritorno con persone che hanno 0 appuntamenti!

Qualche suggerimento per favore?


1
E se volessi ottenere zero | 0 come risultato sulla singola tabella. Ho la tabella vm_tool_licenses e la query è come di seguito seleziona vm_tool_id, count (vm_tool_license_active) dal gruppo vm_tool_licenses da vm_tool_license_active, vm_tool_id con vm_tool_license_active = false`
Narendra

Risposte:


101

Vuoi un join esterno per questo (e devi usare la persona come tabella "guida")

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;

Il motivo per cui funziona è che il join esterno (sinistro) tornerà NULLper quelle persone che non hanno un appuntamento. La funzione aggregata count()non conterà i NULLvalori e quindi otterrai uno zero.

Se vuoi saperne di più sugli outer join, ecco un bel tutorial: http://sqlzoo.net/wiki/Using_Null


ma cosa succede se alcuni dei campi dell'appuntamento NON sono NULL (nella definizione della tabella)?
Lior Yehezkely

@LiorYehezkely: "alcune delle colonne" non importa. Il count () usa la colonna join. Se non è nullo, allora c'è un appuntamento che dovrebbe essere contato
a_horse_with_no_name

21

Devi usare LEFT JOINinvece diINNER 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
Il GROUP BY sembra un errore di battitura nella domanda originale poiché la tabella non è inclusa nella query.
Joachim Isaksson

7

se esegui il join esterno (con il conteggio) e quindi usi questo risultato come una sotto-tabella, puoi ottenere 0 come previsto (grazie alla funzione 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

5

USA join per ottenere il conteggio 0 nel risultato utilizzando GROUP BY.

semplicemente 'join' fa Inner join in MS SQL quindi, vai per il join sinistro o destro.

Se la tabella che contiene la chiave primaria è menzionata per prima nella QUERY, allora usa LEFT join altrimenti RIGHT join.

PER ESEMPIO:

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

Prendi il gruppo per dalla tabella che ha la chiave primaria e conta da un'altra tabella che ha voci / dettagli effettivi.


2

Per modificare ancora meno la tua query originale, puoi trasformare il tuo join in un RIGHTjoin

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;

Questo si basa solo sulla risposta selezionata, ma poiché l'unione esterna è nella RIGHTdirezione, è necessario aggiungere solo una parola e meno modifiche. - Ricorda solo che è lì e a volte può rendere le query più leggibili e richiedere meno ricostruzione.


0

Il problema con un LEFT JOIN è che se non ci sono appuntamenti, restituirà comunque una riga con un null, che quando aggregato per COUNT diventerà 1, e sembrerà che la persona abbia un appuntamento quando in realtà non ne ha nessuno. Penso che questo darà i risultati corretti:

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

Stavo per pubblicare questa stessa soluzione, molto semplice.
Joel
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.