SQL Group Включая пустые строки - PullRequest
6 голосов
/ 10 июня 2011

Ради этого вопроса, давайте предположим, что эта структура таблицы:

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

Places:
PlaceID int PK
Name varchar(50)

Я хочу определить, сколько людей живет в каждом месте:

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

Этот запрос будет опущенместа, где нет людей, живущих там.Есть ли способ заставить его считать 0 вместо?

(я нацеливаюсь на SQL Server 2005, если неважно, что это важно)

РЕДАКТИРОВАТЬ: Вот мой реальный (анонимный) запрос,после попытки адаптировать решение Стива:

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

(перевод между моим первоначальным примером и этим: Foo -> People, FooType -> Places, FooConfig -> третья таблица, для дополнительного удовольствия) я могусделать это с помощью решения Fosco, но я бы предпочел Стив.

Ответы [ 4 ]

4 голосов
/ 10 июня 2011
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

РЕДАКТИРОВАННЫЙ вопрос:

Предполагая, что всегда есть запись FooConfig, мы отбросим LEFT JOIN в эту таблицу (как она всегда будет там).).Затем мы можем включить дополнительные критерии в объединение к таблице 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

Если таблица FooConfig является необязательной, то дополнительные критерии даты не могут использоваться (как они всегдаоценивать как ложное) - поэтому мы должны сделать что-то вроде:

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
1 голос
/ 10 июня 2011

Вы можете использовать запрос столбца

select pla.PlaceID, ISNULL((select COUNT(*) 
                             from People 
                             where PlaceID = pla.PlaceID),0) as peopleCount
from Places as pla
order by PlaceID
0 голосов
/ 10 июня 2011

DateDiff(day, GetDate(), f.Date) > 0 AND DateDiff(day, GetDate(), f.Date) < fc.Days превращает ЛЕВЫЕ СОЕДИНЕНИЯ во ВНУТРЕННИЕ СОЕДИНЕНИЯ, а это не то, что вам нужно.

Чтобы оставить это в левом присоединении, добавьте или значение null (или поместите предложение where в JOIN, как это сделал Стив Мейн)

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
0 голосов
/ 10 июня 2011

COUNT () считает ненулевые значения. Таким образом, вы можете код:

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