SQL:将条目的日期时间最近的行返回到指定时间

时间:2016-02-10 15:20:17

标签: sql sql-server datetime

第一篇文章 - 为那个冗长的问题道歉。使用SQLServer2012

这将更好地说明我的需求:

我有代理商的活动日志 - 每次他们在我们的呼叫中心更改他们的电话状态。每个用户每天可以有几个或几百个。我需要输入一个日期时间,并让它返回每个人的PREVIOUS到该日期时间的状态。

目前,这是我的问题。这段代码告诉我我想要的东西,但减去我需要的一条信息:

SELECT        
MAX(StatusDateTime),
UserId

FROM            
AgentActivityLog 
WHERE
StatusDateTime BETWEEN '2/9/2016 00:00:00' AND '2/9/2016 08:52:12'

GROUP BY 
UserId

order by 2,1

返回一个userid列表,我在2016年2月9日08:52:12之前收到了最新的条目。

2016-02-09 08:02:21.000 AbalosB
2016-02-09 08:06:12.000 AnkenbrD
2016-02-09 07:48:58.000 AzziV
2016-02-09 00:00:00.000 BachmayM

我的问题是我还需要包含另一个包含其所处状态名称的列。当我这样做时,它包含该范围内的每个唯一时间;我假设因为它现在为每个状态选择最大时间 - 而不是仅限最大时间。

将StatusKey添加到Select和Group By时返回的内容示例:

2016-02-09 08:01:43.000 AbalosB     Gone Home
2016-02-09 08:02:21.000 AbalosB     Available
2016-02-09 08:00:50.000 AnkenbrD    Gone Home
2016-02-09 08:04:40.000 AnkenbrD    On ACD Call
2016-02-09 08:06:02.000 AnkenbrD    ACW - After Call Work
2016-02-09 08:06:12.000 AnkenbrD    Available

我需要包含Status列,但我只需要在输入之前输入的条目。我这次使用了一个范围,我可以进入' 2/9/2016 08:52:12'和Id需要输入

3 个答案:

答案 0 :(得分:0)

如果您只需要一条记录,即最新记录,则可以使用TOP

SELECT TOP 1 StatusDateTime, UserId, StatusKey
FROM AgentActivityLog 
WHERE StatusDateTime BETWEEN '2/9/2016 00:00:00' AND '2/9/2016 08:52:12'
ORDER BY StatusDateTime DESC

修改

要获取最新记录每个用户,请使用ROW_NUMBER

SELECT StatusDateTime, UserId, StatusKey
FROM (
  SELECT StatusDateTime, UserId, StatusKey, 
         ROW_NUMBER() OVER (PARTITION BY UserId 
                            ORDER BY StatusDateTime DESC) AS rn
  FROM AgentActivityLog 
  WHERE StatusDateTime BETWEEN '2/9/2016 00:00:00' AND '2/9/2016 08:52:12') t
WHERE t.rn = 1

答案 1 :(得分:0)

使用this jsfiddle和CTE

WITH Data AS (
    SELECT
        StartDateTime,
        UserId,
        StatusKey,
        RANK() OVER(PARTITION BY UserId ORDER BY StartDateTime DESC) r
    FROM AgentActivityLog
    WHERE StatusDateTime BETWEEN '2/9/2016 00:00:00' AND '2/9/2016 08:52:12'

)
SELECT * FROM Data WHERE r = 1

答案 2 :(得分:0)

您可以使用Window函数,假设您在过去十年中使用的是SQL Server版本。您需要将其封装在CTE中,因为Window函数仅在SELECTORDER BY子句中可用:

;WITH MyCTE AS
(
    SELECT
        UserId
        StartDateTime,
        StatusKey,
        ROW_NUMBER() OVER (PARTITION BY UserId ORDER BY StartDateTime) AS row_num
    FROM
        dbo.AgentActivityLog
    WHERE
        StatusDateTime BETWEEN '2/9/2016 00:00:00' AND '2/9/2016 08:52:12'
)
SELECT
    UserId,
    StartDateTime,
    StatusKey
FROM
    MyCTE
WHERE
    row_num = 1

或者,您可以使用子查询:

SELECT
    L.UserId,
    L.StartDateTime,
    L.StatusKey
FROM
    dbo.AgentActivityLog L
INNER JOIN
    (
        SELECT UserId, MAX(StartDateTime) AS MaxStartDateTime
        FROM dbo.AgentActivityLog
        WHERE StatusDateTime BETWEEN '2/9/2016 00:00:00' AND '2/9/2016 08:52:12'
        GROUP BY UserId
    ) SQ ON
        SQ.MaxStartDateTime = L.StartDateTime AND
        SQ.UserId = L.UserId

这两种方法都假定您对给定StartDateTime的{​​{1}}值没有完全重复。

此外,您应该避免使用UserId(或任何列号)并使用实际的列/表达式。使用序数值是一种坏习惯,通常会导致代码出现错误和/或维护问题。