【问题标题】:Finding duplicate values in MySQL在 MySQL 中查找重复值
【发布时间】:2010-10-15 20:53:28
【问题描述】:

我有一个包含 varchar 列的表,我想在该列中查找所有具有重复值的记录。我可以用来查找重复项的最佳查询是什么?

【问题讨论】:

  • 既然您提到查找所有记录,我假设您需要知道该 varchar 列中的 KEYS 以及重复的 VALUES。
  • 得到值后我可以很容易地找到键,我真的只是想要一个所有重复值的列表。

标签: mysql


【解决方案1】:

使用GROUP BY 子句执行SELECT。假设 name 是您要在其中查找重复项的列:

SELECT name, COUNT(*) c FROM table GROUP BY name HAVING c > 1;

这将返回第一列中带有 name 值的结果,并计算该值在第二列中出现的次数。

【讨论】:

  • 但是,如果您无法获取具有重复值的行的 ID,这有什么用呢?是的,您可以对每个重复值进行新的查询匹配,但是否可以简单地列出重复值?
  • @NobleUplift 你可以做一个GROUP_CONCAT(id),它会列出ID。例如,请参阅我的答案。
  • 如果说ERROR: column "c" does not exist LINE 1是什么意思?
  • 我很困惑为什么这是公认的答案以及为什么它有这么多的赞成票。 OP 问道:“我想在此列中查找所有具有重复值的记录。”这个答案返回一个计数表。 -1
  • 对于那些不了解 HAVING 工作原理的人 - 它只是对结果集的过滤器,因此在主查询之后发生。
【解决方案2】:
SELECT varchar_col
FROM table
GROUP BY varchar_col
HAVING COUNT(*) > 1;

【讨论】:

  • 优于@levik 的答案,因为它没有添加额外的列。使其可用于IN()/NOT IN()
  • 这个答案与 levik 的答案完全相同,只是写法不同,因为结果中仍然省略了重复值的 ID。 levik 的答案只是使用了计数的别名,而这个没有。如果您不需要重复计数,也许这个更干净一些。
【解决方案3】:
SELECT  *
FROM    mytable mto
WHERE   EXISTS
        (
        SELECT  1
        FROM    mytable mti
        WHERE   mti.varchar_column = mto.varchar_column
        LIMIT 1, 1
        )

此查询返回完整记录,而不仅仅是不同的 varchar_column's。

此查询不使用COUNT(*)。如果有很多重复,COUNT(*) 很昂贵,你不需要整个COUNT(*),你只需要知道是否有两行具有相同的值。

这是通过相关查询底部的LIMIT 1, 1 实现的(本质上意味着“返回第二行”)。只有在上述第二行存在时,EXISTS 才会返回 true(即,至少有两行具有相同的 varchar_column 值)。

varchar_column 上有一个索引当然会大大加快这个查询的速度。

【讨论】:

  • 非常好。我在查询末尾添加了ORDER BY varchar_column DESC
  • 这应该是公认的答案,因为GROUP BYHAVING 只返回一个可能的重复项。此外,使用索引字段而不是COUNT(*) 的性能,以及ORDER BY 对重复记录进行分组的可能性。
  • 如上面的 cmets 所述,此查询允许您列出所有重复的行。非常有用。
  • 看着这个我完全不明白它是如何工作的。由于外部表中的任何行也将在内表中可用,因此内部条件是否始终为真,因此每行至少将始终匹配自身?我尝试了查询并得到了我怀疑的结果 - 每一行都返回了。但是有这么多的赞成票,我怀疑自己。内部查询是不是缺少诸如“AND mto.idmti.id”之类的东西?当我添加它时,它确实对我有用。
  • @Quassnoi 好的。我试过把它放在 sqlfiddle 上,但我已经放弃了,因为我尝试运行的每个查询,除了创建模式都会超时。我确实发现仅删除“EXISTS”也可以使查询对我正常工作。
【解决方案4】:

根据 levik 的回答来获取重复行的 ID,如果您的服务器支持,您可以执行 GROUP_CONCAT(这将返回一个逗号分隔的 ID 列表)。

SELECT GROUP_CONCAT(id), name, COUNT(*) c
FROM documents
GROUP BY name
HAVING c > 1;

【讨论】:

  • 非常感谢马特。这真的很有帮助!对于那些试图在 phpmyadmin 中更新的人,如果您将 id 与如下函数一起保留:SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...] 它启用内联编辑,并且它应该更新所有涉及的行(或至少第一个匹配的行),但不幸的是,编辑会生成一个Javascript 错误...
  • 你将如何计算有多少 id 会重复?
  • 如何不将所有ID分组,而是从头到尾列出;在它们旁边的列中包含它们各自的值?因此,它没有对它进行分组,而是仅显示 ID 1 及其值、ID 2 及其值。即使 ID 的值相同。
【解决方案5】:

为了获取所有包含重复的数据,我使用了这个:

SELECT * FROM TableName INNER JOIN(
  SELECT DupliactedData FROM TableName GROUP BY DupliactedData HAVING COUNT(DupliactedData) > 1 order by DupliactedData)
  temp ON TableName.DupliactedData = temp.DupliactedData;

TableName = 您正在使用的表。

DupliactedData = 您要查找的重复数据。

【讨论】:

  • 这一行显示了每个重复项。这就是我需要的。谢谢。
【解决方案6】:

假设您的表名为 TableABC 并且您想要的列是 Col 并且 T1 的主键是 Key。

SELECT a.Key, b.Key, a.Col 
FROM TableABC a, TableABC b
WHERE a.Col = b.Col 
AND a.Key <> b.Key

与上述答案相比,这种方法的优势在于它提供了密钥。

【讨论】:

  • +1 因为它很方便。虽然具有讽刺意味的是,结果本身包含重复项(它列出了 a 和 b,然后是 b 和 a。)
  • @FabienSnauwaert 您可以通过比较小于(或大于)来消除一些重复项
  • @TechTravelThink 你的答案很清楚,谢谢你,但在大表上需要一些时间(在更多 20'000 个条目表上大约需要 200 万)并且在显示 25 个第一个结果之后,如果我点击显示下一个,phpmyadmin 显示错误“#1052 - order 子句中的列 'id' 不明确”
【解决方案7】:
SELECT * 
FROM `dps` 
WHERE pid IN (SELECT pid FROM `dps` GROUP BY pid HAVING COUNT(pid)>1)

【讨论】:

  • 不,因为这很可能是最慢的。众所周知,子选择的速度很慢,因为它们会针对返回的每一行执行。
【解决方案8】:

要查找Employee中name列有多少条记录重复,下面的查询很有帮助;

Select name from employee group by name having count(*)>1;

【讨论】:

    【解决方案9】:

    进一步了解@maxyfc's answer,我需要找到所有返回带有重复值的行,以便我可以在MySQL Workbench 中编辑它们:

    SELECT * FROM table
       WHERE field IN (
         SELECT field FROM table GROUP BY field HAVING count(*) > 1
       ) ORDER BY field
    

    【讨论】:

      【解决方案10】:

      我的最终查询在此处包含了一些有帮助的答案 - 结合 group by、count 和 GROUP_CONCAT。

      SELECT GROUP_CONCAT(id), `magento_simple`, COUNT(*) c 
      FROM product_variant 
      GROUP BY `magento_simple` HAVING c > 1;
      

      这提供了两个示例的 ID(逗号分隔)、我需要的条形码以及重复的数量。

      相应地更改表和列。

      【讨论】:

        【解决方案11】:

        我没有看到任何 JOIN 方法,它们在重复方面有很多用途。

        这种方法会给您带来实际翻倍的结果。

        SELECT t1.* FROM my_table as t1 
        LEFT JOIN my_table as t2 
        ON t1.name=t2.name and t1.id!=t2.id 
        WHERE t2.id IS NOT NULL 
        ORDER BY t1.name
        

        【讨论】:

        • 仅供参考 - 如果可能存在超过 1 条重复记录,您将需要“选择不同的 somecol ..”,否则结果将包含找到的重复行的重复项。
        【解决方案12】:

        我看到了上面的结果,如果您需要检查重复的单列值,查询将正常工作。例如电子邮件。

        但是,如果您需要检查更多列并希望检查结果的组合,那么此查询将正常工作:

        SELECT COUNT(CONCAT(name,email)) AS tot,
               name,
               email
        FROM users
        GROUP BY CONCAT(name,email)
        HAVING tot>1 (This query will SHOW the USER list which ARE greater THAN 1
                      AND also COUNT)
        

        【讨论】:

        • 正是需要的!这是我的查询,检查 3 个字段是否重复:SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total&gt;1
        【解决方案13】:
        SELECT t.*,(select count(*) from city as tt
          where tt.name=t.name) as count
          FROM `city` as t
          where (
             select count(*) from city as tt
             where tt.name=t.name
          ) > 1 order by count desc
        

        用您的表格替换 city。 将 name 替换为您的字段名称

        【讨论】:

          【解决方案14】:

          我更喜欢使用窗口函数(MySQL 8.0+)来查找重复项,因为我可以看到整行:

          WITH cte AS (
            SELECT *
              ,COUNT(*) OVER(PARTITION BY col_name) AS num_of_duplicates_group
              ,ROW_NUMBER() OVER(PARTITION BY col_name ORDER BY col_name2) AS pos_in_group
            FROM table
          )
          SELECT *
          FROM cte
          WHERE num_of_duplicates_group > 1;
          

          DB Fiddle Demo

          【讨论】:

            【解决方案15】:
            SELECT 
                t.*,
                (SELECT COUNT(*) FROM city AS tt WHERE tt.name=t.name) AS count 
            FROM `city` AS t 
            WHERE 
                (SELECT count(*) FROM city AS tt WHERE tt.name=t.name) > 1 ORDER BY count DESC
            

            【讨论】:

            • 两次执行相同的子查询似乎效率低下。
            【解决方案16】:

            下面会找到所有使用过多次的product_id。每个 product_id 只能获得一条记录。

            SELECT product_id FROM oc_product_reward GROUP BY product_id HAVING count( product_id ) >1
            

            代码取自:http://chandreshrana.blogspot.in/2014/12/find-duplicate-records-based-on-any.html

            【讨论】:

              【解决方案17】:
              CREATE TABLE tbl_master
                  (`id` int, `email` varchar(15));
              
              INSERT INTO tbl_master
                  (`id`, `email`) VALUES
                  (1, 'test1@gmail.com'),
                  (2, 'test2@gmail.com'),
                  (3, 'test1@gmail.com'),
                  (4, 'test2@gmail.com'),
                  (5, 'test5@gmail.com');
              
              QUERY : SELECT id, email FROM tbl_master
              WHERE email IN (SELECT email FROM tbl_master GROUP BY email HAVING COUNT(id) > 1)
              

              【讨论】:

                【解决方案18】:

                我由此改进:

                SELECT 
                    col, 
                    COUNT(col)
                FROM
                    table_name
                GROUP BY col
                HAVING COUNT(col) > 1; 
                

                【讨论】:

                  【解决方案19】:
                  SELECT DISTINCT a.email FROM `users` a LEFT JOIN `users` b ON a.email = b.email WHERE a.id != b.id;
                  

                  【讨论】:

                  • 值得注意的是,如果要查询的列没有被索引,这会慢得令人难以忍受,甚至可能无法完成。否则,我可以将 a.email 更改为 a.* 并获取所有重复行的 ID。
                  • @NobleUplift 你在说什么?
                  • @Michael 好吧,因为这是三年前我无法测试我使用的任何版本的 MySQL,但我在我选择的列没有索引的数据库上尝试了相同的查询就在上面,所以花了好几秒钟才完成。将其更改为 SELECT DISTINCT a.* 几乎立即解决。
                  • @NobleUplift 好的。我可以理解它很慢......我关心的部分是“可能甚至没有完成”。
                  • @Michael 我不记得我必须在我们系统中的哪个表上运行此查询,但对于那些有几百万条记录的表,他们可能已经完成了,但在一段时间内很长一段时间我都放弃了看它什么时候真正完成。
                  【解决方案20】:
                  SELECT ColumnA, COUNT( * )
                  FROM Table
                  GROUP BY ColumnA
                  HAVING COUNT( * ) > 1
                  

                  【讨论】:

                  • 这是不正确的,因为它还会发现唯一的匹配项。 0 应该是 1。
                  【解决方案21】:

                  要删除具有多个字段的重复行,首先将它们与为唯一不同的行指定的新唯一键相结合,然后使用“分组依据”命令删除具有相同新唯一键的重复行:

                  Create TEMPORARY table tmp select concat(f1,f2) as cfs,t1.* from mytable as t1;
                  Create index x_tmp_cfs on tmp(cfs);
                  Create table unduptable select f1,f2,... from tmp group by cfs;
                  

                  【讨论】:

                  • 能不能也加个解释?
                  • 为什么不使用CREATE TEMPORARY TABLE ...?对您的解决方案进行一些解释会很棒。
                  【解决方案22】:

                  一个非常晚的贡献...以防万一它对任何人有所帮助...我的任务是在银行应用程序中找到匹配的交易对(实际上是账户到账户转账的双方),以确定每个账户间转账交易的“发件人”和“收件人”,所以我们最终得到了:

                  SELECT 
                      LEAST(primaryid, secondaryid) AS transactionid1,
                      GREATEST(primaryid, secondaryid) AS transactionid2
                  FROM (
                      SELECT table1.transactionid AS primaryid, 
                          table2.transactionid AS secondaryid
                      FROM financial_transactions table1
                      INNER JOIN financial_transactions table2 
                      ON table1.accountid = table2.accountid
                      AND table1.transactionid <> table2.transactionid 
                      AND table1.transactiondate = table2.transactiondate
                      AND table1.sourceref = table2.destinationref
                      AND table1.amount = (0 - table2.amount)
                  ) AS DuplicateResultsTable
                  GROUP BY transactionid1
                  ORDER BY transactionid1;
                  

                  结果是DuplicateResultsTable 提供了包含匹配(即重复)事务的行,但它在第二次匹配同一对时也反向提供了相同的事务 id,因此外部 SELECT 用于分组通过第一个事务 ID,这是通过使用 LEASTGREATEST 来确保两个事务 ID 在结果中的顺序始终相同,这使得 GROUP 第一个事务是安全的,从而消除了所有重复的匹配项。在不到 2 秒的时间内浏览近 100 万条记录并识别出 12,000 多个匹配项。当然 transactionid 是主索引,这真的很有帮助。

                  【讨论】:

                    【解决方案23】:
                    Select column_name, column_name1,column_name2, count(1) as temp from table_name group by column_name having temp > 1
                    

                    【讨论】:

                      【解决方案24】:

                      如果你想删除重复使用DISTINCT

                      否则使用此查询:

                      SELECT users.*,COUNT(user_ID) as user FROM users GROUP BY user_name HAVING user &gt; 1;

                      【讨论】:

                        【解决方案25】:

                        作为 Levik 答案的一种变体,它允许您也找到重复结果的 id,我使用了以下内容:

                        SELECT * FROM table1 WHERE column1 IN (SELECT column1 AS duplicate_value FROM table1 GROUP BY column1 HAVING COUNT(*) > 1)
                        

                        【讨论】:

                          【解决方案26】:

                          感谢@novocaine 的出色回答,他的解决方案对我有用。我稍微改变了它以包含重复值的百分比,这在我的情况下是必需的。下面是修改后的版本。它将百分比减少到两个小数位。如果将 ,2 更改为 0,则不显示小数,更改为 1,则显示一位小数,依此类推。

                          SELECT GROUP_CONCAT(id), name, COUNT(*) c, 
                          COUNT(*) OVER() AS totalRecords, 
                          CONCAT(FORMAT(COUNT(*)/COUNT(*) OVER()*100,2),'%') as recurringPecentage
                          FROM table
                          GROUP BY name
                          HAVING c > 1
                          

                          【讨论】:

                            【解决方案27】:

                            尝试使用此查询:

                            SELECT name, COUNT(*) value_count FROM company_master GROUP BY name HAVING value_count > 1;
                            

                            【讨论】:

                              猜你喜欢
                              • 2010-10-25
                              • 2013-05-30
                              • 1970-01-01
                              • 2018-09-05
                              • 2012-08-20
                              • 2015-11-01
                              • 2020-04-12
                              相关资源
                              最近更新 更多