我有一个名为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,非常感谢有关如何实现此类查询结果的任何建议。
感谢。
答案 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;
或强>
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 ;