【问题标题】:SQL remove duplicates - keep the row with least missing value, and fill missing value from duplicate rows if any non-missing value existsSQL 删除重复项 - 保留缺失值最少的行,如果存在任何非缺失值,则从重复行中填充缺失值
【发布时间】:2022-01-20 04:47:51
【问题描述】:

我有一张桌子:

id gender county dob
001 male USA NULL
001 male NULL NULL
002 female FRANCE NULL
002 NULL NULL 28/01/1990

我想根据列 ID 删除很多重复项。我想保留缺失值最少的记录,同时填补其他重复记录的缺失值。

预期的查询输出:

id gender county dob
001 male USA NULL
002 female FRANCE 28/01/1990

如何在 MySQL 中做到这一点?

【问题讨论】:

  • 想象在同一id 的某些列中有2 个不同的非NULL 值。如何选择其中之一?

标签: mysql sql


【解决方案1】:

您可以尝试按id 聚合并取所有其他列的最大值:

SELECT id, MAX(gender) AS gender, MAX(country) AS country, MAX(dob) AS dob
FROM yourTable
GROUP BY id;

【讨论】:

  • 谢谢蒂姆。但是,我的实际表比这个简化的示例有更多的列(总共大约 50 列)。有没有办法不提及所有列名?
  • 遗憾的是,您可能不得不明确提及所有列名。至少,我的方法需要这样做。
  • @crx91 有没有办法不提及所有列名? 没有。但是您可以从 INFORMATION_SCHEMA 获取列名,构建查询文本并作为准备好的语句执行它.
【解决方案2】:
SELECT CONCAT('SELECT id,',
              GROUP_CONCAT(CONCAT('MAX(',
                                  COLUMN_NAME,
                                  ') ',
                                  COLUMN_NAME)
                           ORDER BY ORDINAL_POSITION),
              ' FROM test GROUP BY id')
INTO @sql
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
  AND TABLE_NAME = 'test'
  AND COLUMN_NAME <> 'id';

PREPARE stmt FROM @sql;
EXECUTE stmt;
DROP PREPARE stmt;

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=c7deccefdcbaf2422bc177fb349ad080

在批处理(从程序 - 启用多查询)或存储过程中使用此代码。

id 替换为真实的识别列名(3 个位置)。

test 替换为真实表名(2 个位置)。

如果您不需要输出列的顺序来匹配源表中的顺序,请删除 ORDER BY ORDINAL_POSITION(但 id 将始终是第一个)。

如果需要,用明确的数据库名称替换 DATABASE()

您可以使用任何有效的名称代替@sqlstmt

【讨论】:

    猜你喜欢
    • 2019-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-25
    相关资源
    最近更新 更多