通过包含空行对SQL进行分组

通过包含空行对SQL进行分组,sql,sql-server,group-by,Sql,Sql Server,Group By,为了回答这个问题,让我们假设这个表结构: 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

为了回答这个问题,让我们假设这个表结构:

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,因为它很可能很重要)

编辑: 在尝试调整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
选择
英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺
从FooType改为ft
ft.FooTypeID=f.FooTypeID上的左外连接Foo f
在ft.NotificationConfigID=fc.FooConfigID上左键连接FooConfig fc
哪里
DateDiff(day,GetDate(),f.Date)>0和
DateDiff(天,GetDate(),f.Date)
(我最初的例子和这个例子之间的翻译是:Foo->People,FooType->Places,FooConfig->第三个表,以获得额外的乐趣)
我可以用Fosco的解决方案来解决这个问题,但我更喜欢史蒂夫的

您可以使用列查询

select pla.PlaceID, ISNULL((select COUNT(*) 
                             from People 
                             where PlaceID = pla.PlaceID),0) as peopleCount
from Places as pla
order by 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
COUNT()统计非空值。因此,您可以编写以下代码:

SELECT pla.PlaceID, COUNT(peo.PlaceID) As nbr
FROM Places AS pla
LEFT JOIN People AS peo ON (peo.PlaceID = pla.PlaceID)
DateDiff(day,GetDate(),f.Date)>0和DateDiff(day,GetDate(),f.Date)
将左侧联接转换为您不想要的内部联接

要使其保持左连接add或为null(或者像Steve Mayne那样将where子句放入连接中)

选择
英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺英尺
从FooType改为ft
st.FooTypeID=s.FooTypeID上的左外联接f
在st.NotificationConfigID=fc.FooConfigID上左键连接FooConfig fc
哪里
(DateDiff(day,GetDate(),f.Date)>0
或f.日期为空)
及
(DateDiff(day,GetDate(),f.Date)
它可以工作,但与
JOIN
解决方案相比效率很低,不是吗?太棒了!我能够毫无困难地将它应用于我的真实(更复杂)查询,所以我很高兴!一旦我能够接受……这将是一个非常糟糕的表现(相关子查询逐行操作,应该避免),而且@Steve Mayne从可维护性和性能角度都有一个更好的解决方案。很高兴它能有所帮助。我也喜欢史蒂夫的解决方案。。。有很多方法可以通过SQL获得您想要的东西。对于否决者来说,你知道否决一个有效的解决方案是错误的,对吧?这比我写的案例陈述要简单得多。真不敢相信我没有想到这一点。@Conrad,你到底在说什么?@Steve,你的解决方案的问题是,我真正的查询要复杂得多(我加入了几个表来提取日期和内容),我无法让它工作。我会用一些非常接近我真实的问题来更新我的问题,也许你能帮我。你的第一次修订非常完美!Config列是可选的,但在这种情况下,我并不关心它,所以它工作得非常完美@Steve只是想让你知道我更喜欢你做的事你想从
FooConfig
表中检索什么值?看起来你什么都没做。
fc.Days
,在
WHERE
条款中使用。是-抱歉!这是漫长的一天,我假设
s.FooTypeID
应该是
f.FooTypeID
,而
st
应该是
ft
?FooType->FooConfig是1:0-1还是1:m?FooType->FooConfig是1:0-1。而且,关于FooTypeID,您是正确的。
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
SELECT pla.PlaceID, COUNT(peo.PlaceID) As nbr
FROM Places AS pla
LEFT JOIN People AS peo ON (peo.PlaceID = pla.PlaceID)
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