【问题标题】:Query last event each person attended查询每个人最近参加的活动
【发布时间】:2013-01-05 09:15:04
【问题描述】:

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

谢谢。

【问题讨论】:

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


    【解决方案1】:

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

    使用此 CTE,您可以按某些标准(即您的 EID)对数据进行分区,并让 SQL Server 为每个“分区”从 1 开始为您的所有行编号,并按某些标准排序。

    所以试试这样的:

    ;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 - 所以最新、最近的事件有 RowNum = 1

    这是否符合您的要求??

    【讨论】:

    • 这很聪明。我想这对我有用,谢谢。请问是初始的;那里只是确保在开始 CTE 之前完成任何先前的语句?
    • @user1911175:是的,完全正确 - CTE 本身不需要前导 ; - 但前面的命令必须以分号终止。
    【解决方案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]
    

    【讨论】:

      【解决方案3】:

      你可以这样做:

      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

      【讨论】:

      • 单个选择中的两个 where 子句。错字?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-31
      • 2015-08-08
      • 2021-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多