【问题标题】:Delete all rows except latest per user, having a certain column value删除除每个用户最新的所有行,具有特定的列值
【发布时间】:2012-06-04 08:42:47
【问题描述】:

我有一个表 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)
);

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

【问题讨论】:

  • 我们在帮助那些无法帮助自己或不尝试的人方面非常糟糕。
  • 你的数据库系统是什么?
  • 你试过什么?你离解决方案有多近?请使用该信息更新您的问题。
  • 对于usertimestamp 是唯一的吗?

标签: sql sqlite group-by sql-delete


【解决方案1】:

我认为你应该能够做这样的事情:

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

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

【讨论】:

  • 我正在使用 Sqlite,在 (user, timestamp) 的逗号附近出现语法错误。我会更新我的问题,对您的回答进行一些调整。
【解决方案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' 

【讨论】:

    【解决方案3】:

    在我看来,您的解决方案不够可靠,因为您的子查询正在提取一个既未聚合也未添加到 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 命令实际应用于该实例)。不过,此解决方案确实假设 timestamp 对于 user 来说是唯一的。

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

    【讨论】:

    • 时间戳应该每个用户都是唯一的,但是一些查询表明确实有一些重复。通过这次删除,我最终得到的事件比不同的用户多(select count(0) from events 大于 select count(distinct user) from events),而我显然希望每个用户最多有最后一个“DTV”事件。这可能是时间戳对用户来说不是唯一的直接结果吗?
    • @Bossie:是的,恐怕每个用户的时间戳唯一性对于这个解决方案至关重要。
    猜你喜欢
    • 1970-01-01
    • 2020-09-25
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 2020-11-07
    • 1970-01-01
    相关资源
    最近更新 更多