SQL Server查询 - 在同一个表上计数两次

时间:2011-11-23 09:09:15

标签: sql-server tsql

这个问题一直让我感到疯狂,虽然我很久没有写SQL了。

我有两张桌子:

CREATE TABLE [Entities].[Events](
[EventID] [int] IDENTITY(1,1) NOT NULL,
[EventVenueID] [int] NULL,
[EntityID] [int] NOT NULL,
[OrganisationID] [int] NULL,
[Title] [nvarchar](300) NOT NULL,
[DateStart] [datetime] NOT NULL,
[DateFinish] [datetime] NOT NULL,
[Notes] [nvarchar](max) NULL,
[MinimumProviders] [int] NOT NULL,
[MinimumAttendees] [int] NOT NULL,
[ShowCalendar] [bit] NOT NULL,
[CreationDate] [datetime] NOT NULL,
[IsEnabled] [bit] NOT NULL)

CREATE TABLE [Entities].[EventParticipants](
[ParticipantID] [int] IDENTITY(1,1) NOT NULL,
[EventID] [int] NOT NULL,
[PersonID] [int] NOT NULL,
[ParticipantType] [int] NOT NULL,
[ParticipantStatus] [int] NOT NULL,
[AttendanceStatus] [int] NULL)

一个查询:

SELECT
e.EventID,
ev.VenueName,
e.EntityID,
o.Name AS 'Organisation',
e.Title,
e.DateStart,
e.DateFinish,
e.Notes,
e.MinimumProviders,
e.MinimumAttendees,
e.CreationDate,
COUNT(epp.ParticipantID) AS 'ProvidersConfirmed',
COUNT(epa.ParticipantID) AS 'AttendeesConfirmed',
e.IsEnabled
  FROM
Entities.Events e
  LEFT OUTER JOIN
Entities.EventVenues ev
  ON
e.EventVenueID = ev.EventVenueID
  LEFT OUTER JOIN
Entities.Organisations o
  ON
e.OrganisationID = o.OrganisationID
  LEFT OUTER JOIN
Entities.EventParticipants epp
  ON
e.EventID = epp.EventID AND epp.ParticipantType = 1 AND epp.ParticipantStatus = 3
  LEFT OUTER JOIN
Entities.EventParticipants epa
  ON
e.EventID = epa.EventID AND epa.ParticipantType = 2 AND epa.ParticipantStatus = 3
  GROUP BY
e.EventID,
ev.VenueName,
e.EntityID,
o.Name,
e.Title,
e.DateStart,
e.DateFinish,
e.Notes,
e.MinimumProviders,
e.MinimumAttendees,
e.CreationDate,
e.IsEnabled

计数产生奇怪的结果,例如在EventParticipants表中我有以下数据:

参与者类型= 1(3条记录) 参与者类型= 2(1记录) 参与者状态= 3(4条记录)

查询计数应返回:

ProvidersConfirmed = 3 AttendeesConfirmed = 1

但是,它正在返回

ProvidersConfirmed = 3 AttendeesConfirmed = 3

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:1)

考虑:

COUNT(DISTINCT epp.ParticipantID) AS 'ProvidersConfirmed',
COUNT(DISTINCT epa.ParticipantID) AS 'AttendeesConfirmed'

更接近,但这仍然会计算NULL值,因此......

COUNT(DISTINCT epp.ParticipantID) 
     - MAX(CASE WHEN epp.ParticipantID IS NULL THEN 1 ELSE 0 END)  
     AS 'ProvidersConfirmed',
COUNT(DISTINCT epa.ParticipantID)
     - MAX(CASE WHEN epa.ParticipantID IS NULL THEN 1 ELSE 0 END)
     AS 'AttendeesConfirmed'

答案 1 :(得分:1)

基本上所有联接都抛弃了这个查询。当您从Event加入EventParticipants时,有一条事件记录和三条EventParticipant记录,这相当于数据集中的三个重复的eventID。然后再次加入EventParticipants。因为您要连接3行一行,所以重复结果3次。

有很多方法可以减少结果,但最好只有JOIN一次并在你的聚合中做一些选择性数学运算,如下所示:

SELECT
e.EventID,
ev.VenueName,
e.EntityID,
o.Name AS 'Organisation',
e.Title,
e.DateStart,
e.DateFinish,
e.Notes,
e.MinimumProviders,
e.MinimumAttendees,
e.CreationDate,
COUNT(CASE WHEN ep.ParticipantType = 1 THEN 1 ELSE NULL END) AS 'ProvidersConfirmed',
COUNT(CASE WHEN ep.ParticipantType = 2 THEN 1 ELSE NULL END) AS 'AttendeesConfirmed',
e.IsEnabled
  FROM
Entities.Events e
  LEFT OUTER JOIN
Entities.EventVenues ev
  ON
e.EventVenueID = ev.EventVenueID
  LEFT OUTER JOIN
Entities.Organisations o
  ON
e.OrganisationID = o.OrganisationID
  LEFT OUTER JOIN
Entities.EventParticipants epp
  ON
e.EventID = epp.EventID AND epp.ParticipantStatus = 3
  GROUP BY
e.EventID,
ev.VenueName,
e.EntityID,
o.Name,
e.Title,
e.DateStart,
e.DateFinish,
e.Notes,
e.MinimumProviders,
e.MinimumAttendees,
e.CreationDate,
e.IsEnabled

SQL的COUNT将丢弃所有空值,因此它只会计算唯一值。

答案 2 :(得分:0)

您确定需要Left Outer Join

因为Left Outer Join将从左表中选择所有行。我想这就是问题,所有行都是从事件参与者中选择的。

如果不要求使用INNER,您可能想要使用Outer加入。