查询每个人参加的最后一个活动

时间:2013-01-05 09:15:04

标签: sql sql-server tsql sql-server-2012

我有一个名为CampRegistration的表,其结构如下:

[EID] INT, [CampName] VARCHAR(100), [StartDt] DATETIME

EID是参加营地的人的标识符。我希望选择CampRegistration表中每个人在给定日期之前参加的最后一个营地。

这是我的第一次尝试:

@DECLARE @currentCampDt DATETIME = '2012-8-4';
SELECT [EID], [CampName], MAX([StartDt]) [StartDt]
FROM [CampRegistration]
WHERE [StartDt] < @currentCampDt 
GROUP BY [EID],[CampName]
order by [EID]

这里的问题是,如果有人参加了多个不同名称的营地,我会得到该人的多个结果(每个营地名称的最后一次参加)。我只想为每个人拿回一张单曲,这是他们参加的任何名字的最后一个阵营。我最终需要为每条记录(EID,CampName和营地的StartDt)获取这三条信息,所以我不确定我是否真的可以从Group By删除CampName。

我正在使用SQL Server 2012,非常感谢有关如何实现此类查询结果的任何建议。

感谢。

3 个答案:

答案 0 :(得分:5)

一种方法是使用CTE(公用表表达式)。

使用此CTE,您可以按照某些条件对数据进行分区 - 即EID - 并为每个“分区”提供从1开始的所有行的SQL Server编号,按某些条件排序。

所以尝试这样的事情:

;WITH CampEvents AS
(
   SELECT 
       EID, CampName, StartDt,
       RowNum = ROW_NUMBER() OVER(PARTITION BY EID ORDER BY StartDt DESC)
   FROM 
       dbo.CampRegistration
)
SELECT 
   EID, CampName, StartDt
FROM 
   CampEvents
WHERE
   RowNum = 1

在这里,我只选择每个“分区”的“第一个”条目(即每个EID) - 按降序StartDt排序 - 所以最新的,最近的事件有{{ 1}}。

这会接近你想要的吗?

答案 1 :(得分:2)

这不会很快,但会这样做:

@DECLARE @currentCampDt DATETIME = '2012-8-4';

SELECT o.[EID], o.[CampName], o.[StartDt]
FROM [CampRegistration] o
WHERE o.[StartDt] = ( 
                      SELECT MAX(i.[StartDt]) 
                      FROM [CampRegistration] i WHERE i.[StartDt] < @currentCampDt
                      AND
                      i.[EID] = o.[EID]
                    )
order by o.[EID]

答案 2 :(得分:1)

你可以这样做:

WITH LastCampsAttended
As
(
  SELECT *,
    ROW_NUMBER() OVER(PARTITION BY EID ORDER BY StartDt DESC) AS rownum
  FROM CampRegistration
  WHERE [StartDt] < @currentCampDt 
)
SELECT 
  EID,
  CampName,
  StartDt
FROM LastCampsAttended
WHERE rownum = 1;

SQL Fiddle Demo

SELECT
  camps.*
FROM CampRegistration camps
INNER JOIN 
(
  SELECT EID, MAX(StartDt) LatestDate
  FROM CampRegistration
  GROUP BY EID
) LatestCamps  ON camps.EID = LatestCamps.EID
              AND camps.StartDt = LatestCamps.LatestDate
WHERE camps.StartDt < @currentCampDt ;

Updated SQL fiddle Demo