在MySQL中查找重复值

Jon*_*ury 738 mysql

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

lev*_*vik 1471

SELECT一个GROUP BY条款.假设name是要在以下位置找到重复项的列:

SELECT name, COUNT(*) c FROM table GROUP BY name HAVING c > 1;
Run Code Online (Sandbox Code Playgroud)

这将返回第一列中名称值的结果,以及该值在第二列中出现的次数.

  • 但是,如果您无法获取具有重复值的行的ID,那么这有用吗?是的,您可以为每个重复值执行新的查询匹配,但是是否可以简单地列出重复项? (24认同)
  • @NobleUplift你可以做一个```GROUP_CONCAT(id)```它会列出ID.请参阅我的答案以获取示例. (20认同)
  • 我很困惑为什么这是接受的答案,为什么它有这么多的赞成.OP问道,"我想在本专栏中找到所有具有重复值的记录." 这个答案返回一个计数表.-1 (12认同)
  • 如果它说`ERROR:column"c"不存在LINE 1`会是什么意思? (4认同)
  • 对于那些不了解HAVING如何工作的人 - 它只是对结果集的过滤器,因此在主查询之后发生. (4认同)
  • 我发现使用`having count(*)> 1`更直观 (3认同)

max*_*yfc 220

SELECT varchar_col
FROM table
GROUP BY varchar_col
HAVING COUNT(*) > 1;
Run Code Online (Sandbox Code Playgroud)

  • 优于@ levik的答案,因为它不添加额外的列.使用`IN()`/`NOT IN()`非常有用. (9认同)
  • 这个答案与 levik 的答案完全相同,只是写法不同,因为结果中仍然省略了重复值的 ID。levik 的答案只使用了计数的别名,而这个没有。如果您不需要重复计数,也许这个会更干净一些。 (4认同)

Qua*_*noi 164

SELECT  *
FROM    mytable mto
WHERE   EXISTS
        (
        SELECT  1
        FROM    mytable mti
        WHERE   mti.varchar_column = mto.varchar_column
        LIMIT 1, 1
        )
Run Code Online (Sandbox Code Playgroud)

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

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

varchar_column当然,拥有一个索引会大大加快这个查询的速度.

  • 这应该是公认的答案,因为`GROUP BY`和`HAVING`只返回一个可能的重复项.此外,使用索引字段而不是"COUNT(*)"的性能,以及"ORDER BY"对重复记录进行分组的可能性. (7认同)
  • 很好.我在查询结束时添加了`ORDER BY varchar_column DESC`. (3认同)
  • 如上面的评论所述,此查询允许您列出所有重复的行。很有用。 (3认同)
  • 看着这个,我根本不明白它是如何工作的。内部条件不会一直为真,因为外部表中的任何行也将在内部表中可用,因此每一行至少总是匹配自己吗?我尝试查询,并得到了我怀疑的结果-返回的每一行。但是有这么多的反对我怀疑自己。内部查询是否不丢失“ AND mto.id <> mti.id”之类的内容?当我添加它时,它确实对我有用。 (3认同)
  • @Quassnoi好吧.我已经尝试将它放在sqlfiddle上,但是我已经放弃了,因为我尝试运行的每个查询,除了创建模式时都会超时.我确实发现只需删除"EXISTS"也可以使查询正常工作. (2认同)

Mat*_*don 132

GROUP_CONCAT如果你的服务器支持,你可以根据levik的答案来获取重复行的ID,这将返回逗号分隔的id列表.

SELECT GROUP_CONCAT(id), name, COUNT(*) c FROM documents GROUP BY name HAVING c > 1;
Run Code Online (Sandbox Code Playgroud)

  • 所有这些时间都不知道GROUP_CONCAT()!非常有用. (11认同)
  • 我如何不将所有ID分组,而是从头到尾列出?在它们旁边的列中有它们各自的值?因此,它没有显示分组,而是显示了ID 1及其值,ID 2及其值。即使ID的值相同也是如此。 (2认同)

小智 16

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

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;
Run Code Online (Sandbox Code Playgroud)

TableName = 您正在使用的表。

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


小智 12

SELECT * 
FROM `dps` 
WHERE pid IN (SELECT pid FROM `dps` GROUP BY pid HAVING COUNT(pid)>1)
Run Code Online (Sandbox Code Playgroud)

  • 不,因为这很可能是最慢的。子选择非常慢,因为它们是针对返回的每一行执行的。 (2认同)

Tec*_*ink 11

假设您的表名为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
Run Code Online (Sandbox Code Playgroud)

这种方法优于上述答案的优势在于它给出了密钥.

  • +1因为它很方便.但具有讽刺意味的是,结果本身包含重复项(它列出了a和b,然后是b和a.) (4认同)
  • @FabienSnauwaert您可以通过比较小于(或大于)来消除某些重复项 (2认同)

小智 9

要查找Employee中名称列中有多少记录重复,下面的查询很有用;

Select name from employee group by name having count(*)>1;
Run Code Online (Sandbox Code Playgroud)


Ada*_*her 8

我没有看到任何JOIN aproaches,在重复方面有很多用途.

这个aproeach为您提供实际的双倍结果.

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
Run Code Online (Sandbox Code Playgroud)

  • 仅供参考-如果可能存在多个重复记录,则需要“选择不同的somecol ..”,否则结果将包含找到的重复行的重复。 (2认同)

小智 7

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
Run Code Online (Sandbox Code Playgroud)

用您的表替换城市.将名称替换您的字段名称


Jon*_*han 7

我的最终查询包含了一些有用的答案 - 结合group by,count和GROUP_CONCAT.

SELECT GROUP_CONCAT(id), `magento_simple`, COUNT(*) c 
FROM product_variant 
GROUP BY `magento_simple` HAVING c > 1;
Run Code Online (Sandbox Code Playgroud)

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

相应地更改表格和列.


小智 6

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

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

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)
Run Code Online (Sandbox Code Playgroud)


Abs*_*ERØ 6

@ maxyfc的答案进一步,我需要找到所有与重复的值返回的行,这样我就可以在编辑MySQL工作台

SELECT * FROM table
   WHERE field IN (
     SELECT field FROM table GROUP BY field HAVING count(*) > 1
   ) ORDER BY field
Run Code Online (Sandbox Code Playgroud)


Sco*_*son 5

SELECT ColumnA, COUNT( * )
FROM Table
GROUP BY ColumnA
HAVING COUNT( * ) > 1
Run Code Online (Sandbox Code Playgroud)

  • 这是不正确的,因为它也会发现独特的情况。0 应该是 1。 (3认同)

Luk*_*zda 5

我更喜欢使用窗口函数(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;
Run Code Online (Sandbox Code Playgroud)

数据库小提琴演示


小智 5

我从此改进:

SELECT 
    col, 
    COUNT(col)
FROM
    table_name
GROUP BY col
HAVING COUNT(col) > 1; 
Run Code Online (Sandbox Code Playgroud)