【问题标题】:concat fields that have a duplicate key in common and remove those dupes leaving one连接具有共同重复键的字段并删除那些重复的重复项
【发布时间】:2016-10-11 23:19:54
【问题描述】:

这在上周一直困扰着我,凭借基本知识,我根本无法找到将我们带到需要的地方的解决方案。我搜索了更新、group_concat、concat、joins,但我无法得到我们需要的结果。

问题如下:

我们使用 2 个列来获得我们需要的一个结果:

我们正在开发的数据库:

+------------------------------------+-------------+  
| id                                 | value       |  
+------------------------------------+-------------+  
|  D44172cb5c086c19a4c0286270916bc52 | A           |  
|  D44172cb5c086c19a4c0286270916bc52 | C           |  
|  D44172cb5c086c19a4c0286270916bc52 | B           |  
|  D87d93570cbc9a3edc18601e0aff6e261 | D           |  
|  D87d93570cbc9a3edc18601e0aff6e261 | A           |
|  D87d93570cbc9a3edc18601e0aff6e261 | F           |
+------------------------------------+-------------+ 

我们期望得到的:

 +-------------------------------------+-------------+  
 | id                                  | value       |  
 +-------------------------------------+-------------+  
 |  D44172cb5c086c19a4c0286270916bc52  | A|C|B       |  
 |  D87d93570cbc9a3edc18601e0aff6e261  | D|A|F       |  
 +-------------------------------------+-------------+ 

我们目前正在使用一个 SELECT 命令,该命令有效,并且在名为 valuenew 的临时(因为我们只选择)列中按预期提供数据:

SELECT * GROUP_CONCAT(value SEPARATOR '|') AS valuenew FROM db.table GROUP BY id ;

在连接所需值后,我们如何进行(UPDATEDELETE)查询以删除重复项?因为,使用GROUP_CONCAT 返回的行数将少于实际存在的行数。

我们需要在稍后阶段将连接的值与其他列组合,因此行需要等于返回的行。

解决方案

CREATE TABLE IF NOT EXISTS `temp` 
SELECT *, GROUP_CONCAT(`value` SEPARATOR '|') AS `values`
FROM `db`.`table` 
GROUP BY `id`;

TRUNCATE TABLE `db`.`table`;

UPDATE `temp` SET value = values;
ALTER TABLE `temp` DROP COLUMN values;

INSERT INTO `db`.`table`([all column titles here])
SELECT * 
FROM `db`.`temp`
;

DROP TABLE `db`.`temp`;

【问题讨论】:

  • 这通常是个坏主意,有更多问题的最佳答案涉及撤消这种事情。
  • 不要去规范化,除非你是 100% 永久不可撤销地完全确定你永远不必再将组件值作为单独的值来处理。
  • 如果您不想在所有查询中都写 GROUP_CONCAT(),请定义一个 VIEW 来完成。
  • @MarcB 我们不需要数据,即使我们需要,我们也可以重新调用加载数据文件来恢复所有表。我们需要它,以便在此过程中进一步使用它。 @Barmar 这不是不想使用GROUP_CONCAT,而是要使用一个查询,该查询还将删除它从中提取连接值的重复行。
  • @RkdL 表中有唯一的 ID 列吗?如果您真的想这样做,您需要一种一致的方式来决定将组合值放入哪一行以及应该删除哪些行。这需要另一列来区分每个组中的原始行。

标签: mysql database duplicates concatenation mysql-workbench


【解决方案1】:

如果你真的必须这样做,这可能是最直接的方法。

CREATE TABLE `db`.`temp`
SELECT `id`, GROUP_CONCAT(`value` SEPARATOR '|') AS `value`
FROM `db`.`table` 
GROUP BY `id`;

TRUNCATE TABLE db.table;

INSERT INTO `db`.`table`(`id`, `value`)
SELECT `id`, `value` 
FROM `db`.`temp`
;

DROP TABLE `db`.`temp`

当然,如果还有其他字段,您必须适当考虑它们以防止数据丢失。 您也可以将temp 表设为真正的TEMPORARY 表,但如果您在截断和重新插入之间失去连接,您将丢失所有数据。

编辑:还要确保value 字段可以保存最长的 GROUP_CONCAT() 结果。

【讨论】:

  • 我们仍然需要剩余的值,而不是包含重复标识符的行。实际的表格由 24 列信息组成,介于两者之间。
  • @RkdL 您仍然可以使用此解决方案,只需将所有其他列添加到临时表中。
  • 我正试图让这个解决方案发挥作用,但我的知识又一次用完了。第一个SELECT 给了我一个重复的列名错误,更改名称会将额外的列复制到临时表中,并且由于它在table 表中不存在,因此无法将其复制回来。我可以用创建的新值以某种方式覆盖或update 现有的“值”列吗?
  • 完成了。我在truncate 之后添加了 2 行。 UPDATE temp` 设置值 = 值; ALTER TABLE temp DROP COLUMN 值;`
  • @RkdL 只是让您知道,您遇到问题的原因是因为您使用 * 而不是指定字段;此外,如果指定了字段,则可以避免使用 ALTER TABLE DROP COLUMN 语句。
【解决方案2】:

创建一个生成连接值的视图,而不是更新表。

CREATE VIEW yourtable_view
SELECT id, GROUP_CONCAT(value ORDER BY value SEPARATOR '|') AS values
FROM yourtable
GROUP BY id;

然后在需要使用非规范化值的查询中使用此视图。

如果你真的需要按照自己的方式来做,你的表需要在每个组中的另一列可以用来区分行,所以我们可以更新组中的第一行并删除剩余的行;如果您有 auto_increment 列,则可以使用它。我会在下面调用这个unique_id

-- First add the concatenated values to the first row in each group
UPDATE yourTable AS t1
JOIN (SELECT id, MIN(unique_id) AS first_id, GROUP_CONCAT(value ORDER BY value SEPARATOR '|') AS newvalues
      FROM yourTable
      GROUP BY id
      HAVING COUNT(*) > 1) AS t2
ON t1.id = t2.id AND t1.unique_id = t2.first_id
SET t1.value = t2.values;

-- Then delete all the remaining rows in each group
DELETE t1.*
FROM yourTable AS t1
JOIN (SELECT id, MIN(unique_id) AS first_id
      FROM yourTable
      GROUP BY id
      HAVING COUNT(*) > 1) AS t2
ON t1.id = t2.id AND t1.unique_id > t2.first_id;

DEMO

【讨论】:

  • 最终我们希望使用这些值与其他列连接,因此新值中返回的行数需要等于表中的总行数。重复存在的唯一原因是因为它们是以这种方式提供给我们的。假设 5 行中的每一行除了我们需要的 value 列外完全相同,所以我们不需要其他 4 行,它会无缘无故地炸毁表格。我们正在处理一个 60k 行的表,我们可以减少到 10k 这样做。对您对此的想法感兴趣。
  • 只是不要回来询问如何搜索单个值或如何在不重复的情况下添加新值。 SQL 中的分隔列表很难做到这些。
  • 你应该使用逗号作为分隔符,这样你就可以使用FIND_IN_SET来搜索东西了。
  • 由于某种原因,我们得到一个错误代码 1054(未知列 id),而它显然存在。我们确实有一个额外的独特列可以用于unique_id,涵盖了这么多。
  • 我有一些语法错误,我已经更正了。查看工作演示。
猜你喜欢
  • 2020-07-15
  • 1970-01-01
  • 1970-01-01
  • 2013-04-23
  • 2018-05-07
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
  • 1970-01-01
相关资源
最近更新 更多