删除除最新的每个用户之外的所有行,具有特定的列值

时间:2012-06-04 08:42:47

标签: sql sqlite group-by sql-delete

我有一个包含用户事件的表events,例如:

PK | user | event_type | timestamp
--------------------------------
1  | ab   | DTV        | 1
2  | ab   | DTV        | 2
3  | ab   | CPVR       | 3
4  | cd   | DTV        | 1
5  | cd   | DTV        | 2
6  | cd   | DTV        | 3

我想要做的是每个user只保留一个事件,即具有最新timestampevent_type = 'DTV'的事件。

将删除应用于上面的示例后,表格应如下所示:

PK | user | event_type | timestamp
--------------------------------
2  | ab   | DTV        | 2
6  | cd   | DTV        | 3

你们中的任何一个人都可以提出完成这项任务的东西吗?

更新:我使用的是Sqlite。这就是我到目前为止所做的:

delete from events
where id not in (
  select id from (
    select id, user, max(timestamp)
    from events
    where event_type = 'DTV'
    group by user)
);

我很确定这可以改进。有什么想法吗?

3 个答案:

答案 0 :(得分:3)

我认为你应该可以做这样的事情:

delete from events
where (user, timestamp) not in (
    select user, max(timestamp)
    from events
    where event_type = 'DTV'
    group by user
)

您可能会执行一些更复杂的技巧,例如表格或分区替换,具体取决于您正在使用的数据库

答案 1 :(得分:2)

如果使用sql server roo5 / 2008,则使用以下sql:

;WITH ce 
     AS (SELECT *, 
                Row_number() 
                  OVER ( 
                    partition BY [user], event_type 
                    ORDER BY timestamp DESC) AS rownumber 
         FROM   emp) 
DELETE FROM ce 
WHERE  rownumber <> 1 
        OR event_type <> 'DTV' 

答案 2 :(得分:1)

您的解决方案在我看来似乎不够可靠,因为您的子查询正在拉动既未汇总也未添加到GROUP BY的列。我的意思是,我不是一位经验丰富的SQLite用户,而且您的解决方案确实有效when I tested it。如果在这种情况下确认id列始终可靠地与MAX(timestamp)值相关,那么很好,您的方法似乎相当不错。

但如果您对我的解决方案不确定,可以尝试以下方法:

DELETE FROM events
WHERE NOT EXISTS (
  SELECT *
  FROM (
    SELECT MAX(timestamp) AS ts
    FROM events e
    WHERE event_type = 'DTV'
      AND user = events.user
  ) s
  WHERE ts = events.timestamp
);

events的内部实例分配了一个不同的别名,以便events别名可用于明确引用表的外部实例(实际为DELETE命令的实例适用于)。不过,此解决方案确实timestampuser都是唯一的。

可以使用on SQL Fiddle运行并播放工作示例。