2011-06-10 16 views
6

En aras de esta pregunta, supongamos que esta estructura de la tabla:Grupo de SQL Al incluir las filas vacías

People: 
PersonID int PK 
Name varchar(50) 
Place int NULL FK -> Places.PlaceID 
MovedIn datetime 

Places: 
PlaceID int PK 
Name varchar(50) 

quiero para determinar cuántas personas viven en cada lugar:

SELECT pla.PlaceID, COUNT(*) 
FROM Places AS pla 
LEFT JOIN People as peo ON peo.PlaceID = pla.PlaceID 
GROUP BY pla.PlaceID 

Esta consulta omitirá lugares que no tengan personas viviendo allí. ¿Hay alguna manera de hacer que cuente 0 en su lugar?

(estoy que apuntan a SQL Server 2005, en la remota posibilidad de que importe)

EDIT: Aquí está mi verdadera (anónima) de consulta, después de tratar de adaptar la solución de Steve:

SELECT 
    ft.FooTypeID, COUNT(f.FooID) 
FROM FooType as ft 
LEFT OUTER JOIN Foo f ON ft.FooTypeID = f.FooTypeID 
LEFT JOIN FooConfig fc ON ft.NotificationConfigID = fc.FooConfigID 
WHERE 
    DateDiff(day, GetDate(), f.Date) > 0 AND 
    DateDiff(day, GetDate(), f.Date) < fc.Days 
GROUP BY ft.FooTypeID 

(La traducción entre mi ejemplo inicial y este es: Foo -> Personas, FooType -> Lugares, FooConfig -> Una tercera mesa, para mayor diversión) Puedo hacer que esto funcione con la solución de Fosco, pero preferiría la de Steve.

+0

¿Qué valor que desea recuperar de la tabla 'FooConfig'? Parece que no estás haciendo nada con eso. –

+0

'fc.Days', utilizado en la cláusula' WHERE' –

+0

¡Oh, sí, lo siento! Ha sido un día largo –

Respuesta

3
SELECT pla.PlaceID, COUNT(peo.PersonID) 
FROM Places AS pla LEFT OUTER JOIN People as peo ON peo.PlaceID = pla.PlaceID 
GROUP BY pla.PlaceID 

pregunta Editado:

Suponiendo que no siempre es una entrada FooConfig, Vamos a dejar la LEFT JOIN a la mesa (ya que' ll siempre estará allí). entonces podemos incluir los criterios adicionales en la combinación con la tabla Foo:

SELECT 
    ft.FooTypeID, COUNT(f.FooID) 
FROM FooType as ft 
    JOIN FooConfig fc ON ft.NotificationConfigID = fc.FooConfigID 
    LEFT OUTER JOIN Foo f ON ft.FooTypeID = f.FooTypeID AND 
    DateDiff(day, GetDate(), f.Date) > 0 AND 
    DateDiff(day, GetDate(), f.Date) < fc.Days 
GROUP BY ft.FooTypeID 

Si la tabla FooConfig es opcional, a continuación, los criterios de fecha adicionales no se pueden utilizar (como siempre lo evaluarían en false) - por lo tendríamos que hacer algo como:

SELECT 
    ft.FooTypeID, COUNT(f.FooID) 
FROM FooType as ft 
    LEFT OUTER JOIN FooConfig fc ON ft.NotificationConfigID = fc.FooConfigID 
    LEFT OUTER JOIN Foo f ON ft.FooTypeID = f.FooTypeID AND 
    (
     (DateDiff(day, GetDate(), f.Date) > 0 AND 
     DateDiff(day, GetDate(), f.Date) < fc.Days) 
     OR 
     (fc.Days IS NULL) 
    ) 
GROUP BY ft.FooTypeID 
+0

Eso es mucho más simple que la declaración del caso que escribí. No puedo creer que no haya pensado en eso. – HLGEM

+0

+1 para recordar el 'GROUP BY' –

+0

@Conrad, ¿por qué estás hablando? –

1

Puede utilizar una consulta de columna

select pla.PlaceID, ISNULL((select COUNT(*) 
          from People 
          where PlaceID = pla.PlaceID),0) as peopleCount 
from Places as pla 
order by PlaceID 
+0

sintaxis actualizada, se olvidó de alias la tabla. – Fosco

+0

Funcionará, pero es ineficiente en comparación con la solución 'JOIN', ¿no es así? –

+0

¡Más excelente! Pude adaptarlo a la consulta real (mucho más complicada) sin ningún problema, ¡así que estoy feliz! Tan pronto como pueda aceptar ... –

0

COUNT() cuenta los valores no NULOS. Por lo que puede codificar:

SELECT pla.PlaceID, COUNT(peo.PlaceID) As nbr 
FROM Places AS pla 
LEFT JOIN People AS peo ON (peo.PlaceID = pla.PlaceID) 
0

DateDiff(day, GetDate(), f.Date) > 0 AND DateDiff(day, GetDate(), f.Date) < fc.Days convierte la IZQUIERDA JOINs en un uniones internas que no es lo que quiere.

mantenerlo en combinación izquierda agregar o es nula (o poner la cláusula where al unirse como lo hizo Steve Mayne)

SELECT 
    ft.FooTypeID, COUNT(f.FooID) 
FROM FooType as ft 
LEFT OUTER JOIN Foo f ON st.FooTypeID = s.FooTypeID 
LEFT JOIN FooConfig fc ON st.NotificationConfigID = fc.FooConfigID 
WHERE 
    (DateDiff(day, GetDate(), f.Date) > 0 
     or f.Date IS NULL) 
    AND 
    (DateDiff(day, GetDate(), f.Date) < fc.Days 
     or fc.Days Is NULLL or f.Date Is NULL) 
GROUP BY ft.FooTypeID 
Cuestiones relacionadas