【问题标题】:How to merge duplicate records in MySQLMySQL如何合并重复记录
【发布时间】:2023-03-05 06:49:01
【问题描述】:

我有 1100 万行的 post_view_counters 表。

id    post_id    start_date    end_date    views
_________________________________________________
1       55          XXXX         YYYY        90
2       55          XXXX         YYYY        1
3       55          XXXX         YYYY        1

由于某种原因(后端中的错误)存在重复记录,这些记录已经修复。 我需要合并具有相同 post_idstart_dateend_date 的所有行视图 更新表格后的结果应该是这样的

id    post_id    start_date    end_date    views
_________________________________________________
1       55          XXXX         YYYY        92

【问题讨论】:

  • 表是 MyISAM 还是 InnoDB ?表上是否定义了任何索引?您是否要直接在生产中进行此更改(例如当您的应用程序实际使用表时)?由于是一张大桌子,答案会因影响生产的严重程度而异。
  • start_date end_date 对于所有行都应该相同
  • 所以您想删除重复项,以便表格上只剩下一行,但查看次数正确
  • @RiggsFolly 是的,只有一行更新了视图

标签: php mysql large-data


【解决方案1】:

首先,您必须为每个post_id, start_date, end_date 更新具有最小id 的行:

update tablename t inner join (
  select sum(views) views, min(id) id from tablename
  group by post_id, start_date, end_date
) tt
on tt.id = t.id 
set t.views = tt.views;

然后删除所有其他id,只保留最小id

delete t 
from tablename t inner join tablename tt
on tt.post_id = t.post_id 
and tt.start_date = t.start_date and tt.end_date = t.end_date 
and t.id > tt.id;

由于这是一个大表,因此需要适当的索引以使进程尽可能快地运行。

请参阅demo
对于此表:

CREATE TABLE tablename (
  `id` INTEGER,
  `post_id` INTEGER,
  `start_date` VARCHAR(4),
  `end_date` VARCHAR(4),
  `views` INTEGER
);

INSERT INTO tablename
  (`id`, `post_id`, `start_date`, `end_date`, `views`)
VALUES
  ('1', '55', 'XXXX', 'YYYY', '90'),
  ('2', '55', 'XXXX', 'YYYY', '1'),
  ('3', '55', 'XXXX', 'YYYY', '1'),
  ('4', '65', 'AAAA', 'BBBB', '10'),
  ('5', '65', 'AAAA', 'BBBB', '2'),
  ('6', '65', 'AXXX', 'BYYY', '100'),
  ('7', '65', 'AXXX', 'BYYY', '200'),
  ('8', '75', 'CCCC', 'CCCC', '1');

结果:

| id  | post_id | start_date | end_date | views |
| --- | ------- | ---------- | -------- | ----- |
| 1   | 55      | XXXX       | YYYY     | 92    |
| 4   | 65      | AAAA       | BBBB     | 12    |
| 6   | 65      | AXXX       | BYYY     | 300   |
| 8   | 75      | CCCC       | CCCC     | 1     |

【讨论】:

    【解决方案2】:

    我会采取安全的方法:

    首先,新建一个表——

    CREATE TABLE post_view_counters_new LIKE post_view_counters;
    

    然后将数据插入到新表中——(@scaisEdge 的语法)

    INSERT INTO post_view_counters_new 
    SELECT MIN(id) id,  post_id ,   start_date ,   end_date ,   SUM( views) views
    FROM post_view_counters
    GROUP  BY  post_id ,   start_date ,   end_date; 
    

    之后,比较新表和旧表的数据。满意后,将旧表重命名为“post_view_counters_old”,并将“post_view_counters_new”重命名为“post_view_counters”。因此,如果您在新表中缺少任何内容,您仍然可以参考旧表。

    【讨论】:

    • 好答案+1;但同样是直接delete 更好还是create .. insert 方法;从性能的角度来看,这完全取决于实际存在多少重复行。
    【解决方案3】:

    你可以试试下面-

    select min(id),post_id,    start_date ,   end_date,sum(views)
    from tablename
    group by post_id, start_date, end_date
    

    【讨论】:

    • 伙计们,请参阅comment 并在下方回答
    【解决方案4】:

    对于相同的 post_id , start_date , end_date 你可以使用聚合函数 作为 min(id) , sum(view ) 和 group by

    select min(id) id,  post_id ,   start_date ,   end_date ,   sum( views) views
    from my_table  
    group  by  post_id ,   start_date ,   end_date
    

    【讨论】:

    • 我不需要 select ,我需要在 table 中更新所有行
    • 各位,见comment并在下方回答
    猜你喜欢
    • 1970-01-01
    • 2019-10-14
    • 1970-01-01
    • 2021-06-22
    • 2016-09-26
    • 2013-01-02
    • 1970-01-01
    • 2015-04-23
    • 2019-02-09
    相关资源
    最近更新 更多