2011-06-10 48 views
6

对于这个问题起见,我们假设该表的结构:SQL集团通过包括空行

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的解决方案工作,但我更喜欢Steve的。

+0

你想从'FooConfig'表中检索什么样的价值?看起来你没有做任何事情。 – 2011-06-10 19:18:26

+0

'fc.Days',在'WHERE'子句中使用 – 2011-06-10 19:21:36

+0

噢 - 是的 - 对不起!这是一个漫长的一天 – 2011-06-10 19:23:09

回答

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 

编辑的问题:

假设总有一个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表是可选的,那么多余的日期条件不能用(因为他们总是为false) - 所以我们不得不这样做:

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

这比我写的案例陈述简单得多。不能相信我没有想到这一点。 – HLGEM 2011-06-10 19:04:57

+0

+1记住'GROUP BY' – 2011-06-10 19:04:59

+0

@Conrad,为什么你在说什么? – 2011-06-10 19:08:24

1

您可以使用列查询

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

更新后的语法,忘了别名了。 – Fosco 2011-06-10 19:00:55

+0

它会起作用,但与JOIN解决方案相比效率不高,不是吗? – 2011-06-10 19:03:37

+0

最优秀!我可以毫不费力地将它适应于真实(更加复杂)的查询,所以我很高兴!不久我就能接受...... – 2011-06-10 19:05:35

0

COUNT()计数非空值。所以,你可以将代码:

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接通LEFT JOIN的为内部联接这是不是你想要的。

为了保持一个LEFT JOIN添加或为空(或将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