【问题标题】:Ignore subsequent equivalent rows in mysql select忽略mysql select中的后续等效行
【发布时间】:2018-11-19 16:05:47
【问题描述】:

我需要删除历史日志数据中的冗余。所以给出下表:

 --------------------------------------
|  entity_id  |  action  |   date      |
 --------------------------------------
|      1      |    'A'   | 2018-01-01  |
|x     1      |    'A'   | 2018-01-01  |
|      1      |    'B'   | 2018-01-01  |
|      1      |    'A'   | 2018-01-02  |
|      8      |    'A'   | 2018-01-02  |
|x     1      |    'A'   | 2018-01-03  |
|x     8      |    'A'   | 2018-01-04  |
|x     1      |    'A'   | 2018-01-05  |
|      1      |    'B'   | 2018-01-05  |
 --------------------------------------

我想删除带有 (x) 的那些。简而言之,我想忽略实体随后采取的任何具有相同操作的行。因此,我想要一个返回以下结果的查询

 --------------------------------------
|  entity_id  |  action  |   date      |
 --------------------------------------
|      1      |    'A'   | 2018-01-01  |
|      1      |    'B'   | 2018-01-01  |
|      1      |    'A'   | 2018-01-02  |
|      8      |    'A'   | 2018-01-02  |
|      1      |    'B'   | 2018-01-05  |
 --------------------------------------

以编程方式,删除这些冗余很容易,但使用纯 SQL,我有点迷茫。对 SQL 查询足够了解的人将如何处理这个问题?

谢谢

编辑:基本上,对于实体1,日志中的连续动作是A->A->B->A->A->A->B,我想要一个返回带有这些动作A->B->A->B的行的选择

【问题讨论】:

  • 为什么排除1 | 'A' | 2018-01-031 | 'A' | 2018-01-05而保留1 | 'A' | 2018-01-02
  • 因为(1, 'B', 2018-01-02)已经发生了。基本上,对于实体1,日志中的连续操作是A->A->B->A->A->A->B,我想要一个返回带有这些操作A->B->A->B 的行的选择。我可能会将其添加到编辑中
  • 在您想要的样本中,您有A>B>A>A>B
  • 第四行属于实体8。我包括8 以表明日志由不同的实体组成。其他实体的后续行动也应该被忽略。
  • 您没有 PRIMARY KEY,这使得此类问题基本上无法解决(或至少毫无意义)。

标签: mysql sql logging data-cleaning redundancy


【解决方案1】:

如果行是按日期顺序添加的。

select entity_id, action, min(date)
from table
group by entity id, action

【讨论】:

  • 第一个查询似乎只为实体的每个操作选择一行(即,一旦它看到 (1, 'A') 行,它将忽略所有其他行,甚至是非后续行)。
  • 第二次查询失败,出现以下sql错误Expression #3 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'date'
【解决方案2】:

您希望每个实体都有最新操作的行。我会这样做:

select t.*
from t
where t.date = (select min(t2.date)
                from t t2
                where t2.entity_id = t.entity_id and t2.action = t.action
               );

编辑:

在 MySQL 8+ 中,您只需使用 lag():

select t.*
from (select t.*,
             lag(action) over (partition by entity_id order by date) as prev_action
      from t
     ) t
where prev_action is null or prev_action > action;

您可以在以前的 MySQL 版本中执行类似的操作,但如果可用,窗口函数会更简单。

【讨论】:

  • 您想要每个实体的最新操作的行不,如果您在他发布的示例中看到,OP 肯定不希望这样做。
  • @forpas 。 . .您是否真的因为它使用MAX() 而不是MIN() 而否决了答案?一个简单的注释就足够了。
  • 在 OP 编辑​​后我认为 MIN 也不是问题
猜你喜欢
  • 2011-11-18
  • 2012-04-08
  • 1970-01-01
  • 2017-12-15
  • 2013-02-03
  • 2021-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多