根据列的组合选择行,但只选择最新的时间戳

时间:2012-09-04 11:08:34

标签: sql

给出一个带有列

的非常简化的表
  Name, Action, Status,   Timepoint
1 "A"   "Open"  "OK"      "2012-09-04 10:10:00"
2 "A"   "Close" "OK"      "2012-09-04 10:05:00"
3 "A"   "Close" "ERROR"   "2012-09-04 10:02:00"
4 "B"   "Look"  "NICE"    "2012-09-04 10:05:00"
5 "B"   "Blow"  "COLD"    "2012-09-04 10:00:00"
6 "C"   "Laugh" "OK"      "2012-09-04 10:02:00"
7 "C"   "Laugh" "MUTE"    "2012-09-04 10:00:00"

如何最有效地为名称操作的组合选择每一行,但仅限于最新 Action 的组合时间点? 在上面的例子中,它将返回行

1, 2, 4, 5, 6

工作实现获取行并使用子查询仅在0行具有相同名称操作更新时间点的组合时才返回。但是,当数据集变大时,这似乎非常低效。就像这样

SELECT Name, Action, Status, Timepoint
FROM foobar
WHERE Name IN (... Names of interest ...) AND 
Status IN (... statuses of interest ...) AND
(SELECT COUNT(*) FROM foobar AS t2 WHERE t2.Name = Name AND t2.Status = Status AND t2.Timepoint > Timepoint) = 0
order by Name, Timepoint

4 个答案:

答案 0 :(得分:1)

Select *
from 
(
      select *,
             row_number() over (partition by Name, Action order by timepoint desc) RN
      from yourtable
) v
where RN = 1

答案 1 :(得分:0)

SELECT Name, Action, Status, MIN(Timepoint)
FROM foobar
WHERE Name IN (... Names of interest ...) AND 
Status IN (... statuses of interest ...)
GROUP BY Name, Status, Action

答案 2 :(得分:0)

SELECT Name, Action, Status, TimePoint
FROM foobar f1
     JOIN (SELECT Name, Status, MAX(TimePoint) as TimePoint
           FROM foobar
           GROUP BY Name, Status) f2 
          ON f1.Name = f2.Name
               AND f1.Status = f2.Status
               AND f1.TimePoint = f2.TimePoint

答案 3 :(得分:0)

使用ROW_NUMBER隔离所需的行。我喜欢使用只有id的CTE然后再加入原始表。这样,被过滤的行没有那么多的包袱。

-- setup
DECLARE @temp TABLE(id INT,name CHAR(1),Action VARCHAR(5),Status VARCHAR(5),Timepoint DATETIME)
INSERT INTO @temp (id,name,Action,Status,Timepoint)VALUES
 (1,'A','Open','OK','2012-09-04 10:10:00')
,(2,'A','Close','OK','2012-09-04 10:05:00')
,(3,'A','Close','ERROR','2012-09-04 10:02:00')
,(4,'B','Look','NICE','2012-09-04 10:05:00')
,(5,'B','Blow','COLD','2012-09-04 10:00:00')
,(6,'C','Laugh','OK','2012-09-04 10:02:00')
,(7,'C','Laugh','MUTE','2012-09-04 10:00:00')

-- solution
;WITH groups AS
(
    SELECT
          id
        , rowNum = ROW_NUMBER() OVER(
            PARTITION BY Name,Action 
            ORDER BY Timepoint DESC)
    FROM @temp
)
SELECT temp.id, name, Action, Status, Timepoint
FROM groups INNER JOIN @temp temp ON temp.id = groups.id
WHERE rowNum = 1