ค้นหาค่าที่ซ้ำกันใน MySQL


769

ฉันมีตารางที่มีคอลัมน์ varchar และฉันต้องการค้นหาระเบียนทั้งหมดที่มีค่าซ้ำกันในคอลัมน์นี้ แบบสอบถามที่ดีที่สุดที่ฉันสามารถใช้เพื่อค้นหารายการที่ซ้ำกันคืออะไร


1
เนื่องจากคุณพูดถึงค้นหาระเบียนทั้งหมดฉันถือว่าคุณจำเป็นต้องรู้คีย์และค่าซ้ำซ้อนในคอลัมน์ varchar นั้น
TechTravelThink

ฉันสามารถหากุญแจได้ง่ายพอหลังจากได้รับค่าฉันแค่ต้องการรายการค่าที่ซ้ำกันทั้งหมด
Jon Tackabury

คำตอบ:


1521

ทำSELECTด้วยGROUP BYประโยค สมมติว่าชื่อคือคอลัมน์ที่คุณต้องการค้นหารายการที่ซ้ำกันใน:

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

สิ่งนี้จะส่งคืนผลลัพธ์ที่มีค่าชื่อในคอลัมน์แรกและนับจำนวนครั้งที่ค่านั้นปรากฏในวินาที


27
แต่สิ่งนี้มีประโยชน์อย่างไรถ้าคุณไม่สามารถรับ ID ของแถวด้วยค่าซ้ำกันได้? ใช่คุณสามารถทำการสืบค้นใหม่สำหรับค่าที่ซ้ำกันแต่ละรายการ แต่เป็นไปได้หรือไม่ที่จะระบุรายการที่ซ้ำกัน
NobleUplift

23
@NobleUplift คุณสามารถทำได้GROUP_CONCAT(id)และมันจะแสดงรายการรหัส ดูคำตอบของฉันสำหรับตัวอย่าง
Matt Rardon

5
มันจะหมายความว่าอะไรถ้ามันพูดERROR: column "c" does not exist LINE 1?
ผู้ใช้

15
ฉันสับสนว่าทำไมนี่เป็นคำตอบที่ยอมรับได้และทำไมมันถึงมี upvotes มากมาย OP ถามว่า "ฉันต้องการค้นหาระเบียนทั้งหมดที่มีค่าซ้ำกันในคอลัมน์นี้" คำตอบนี้จะส่งกลับจำนวนสารบัญ -1
โมนิก้า Heddneck

4
สำหรับผู้ที่ไม่เข้าใจการทำงานของ HAVING - เป็นเพียงตัวกรองในชุดผลลัพธ์ดังนั้นเกิดขึ้นหลังจากการสืบค้นหลัก
John Hunt

236
SELECT varchar_col
FROM table
GROUP BY varchar_col
HAVING COUNT(*) > 1;

10
เหนือกว่าคำตอบของ @ levik เนื่องจากไม่ได้เพิ่มคอลัมน์เพิ่มเติม ทำให้มันมีประโยชน์สำหรับใช้กับ/IN() NOT IN()
wmassingham

172
SELECT  *
FROM    mytable mto
WHERE   EXISTS
        (
        SELECT  1
        FROM    mytable mti
        WHERE   mti.varchar_column = mto.varchar_column
        LIMIT 1, 1
        )

แบบสอบถามนี้ส่งกลับระเบียนที่สมบูรณ์ไม่ได้เป็นเพียงที่แตกต่างกันvarchar_columnของ

COUNT(*)แบบสอบถามนี้ไม่ได้ใช้ หากมีจำนวนมากซ้ำCOUNT(*)มีราคาแพงและคุณไม่ต้องการทั้งหมดCOUNT(*)คุณเพียงแค่ต้องรู้ว่ามีสองแถวที่มีค่าเท่ากันหรือไม่

แน่นอนว่าการมีดัชนีตามvarchar_columnประสงค์จะทำให้การสืบค้นนี้รวดเร็วขึ้น


3
ดีมาก. ฉันเพิ่มลงORDER BY varchar_column DESCในส่วนท้ายของแบบสอบถาม
trante

8
นี่ควรเป็นคำตอบที่ได้รับการยอมรับซึ่งเป็นGROUP BYและHAVINGส่งกลับรายการที่ซ้ำซ้อนเพียงรายการเดียว นอกจากนี้ประสิทธิภาพการทำงานที่มีเขตข้อมูลที่จัดทำดัชนีแทนCOUNT(*)และความเป็นไปได้ที่ORDER BYจะจัดกลุ่มระเบียนที่ซ้ำกัน
Rémi Breton

1
ตามที่ระบุไว้ในความคิดเห็นด้านบนแบบสอบถามนี้ช่วยให้คุณสามารถแสดงรายการแถวที่ซ้ำกันทั้งหมด มีประโยชน์มาก.
TryHarder

4
เมื่อมองดูสิ่งนี้ฉันไม่เข้าใจว่ามันจะทำงานได้อย่างไร สภาพภายในจะไม่เป็นจริงหรือไม่เนื่องจากแถวใด ๆ ในตารางด้านนอกจะมีอยู่ในตารางด้านในด้วยดังนั้นอย่างน้อยทุกแถวจะจับคู่ตัวเองเสมอ ฉันลองใช้คิวรีและได้ผลลัพธ์ที่ฉันสงสัย - ทุกแถวกลับมา แต่ด้วย upvotes มากมายฉันสงสัยในตัวเอง ข้อความค้นหาภายในไม่มีอะไรเหมือน "AND mto.id <> mti.id" หรือไม่ มันใช้งานได้สำหรับฉันเมื่อฉันเพิ่ม
Clox

2
@Quassnoi เอาล่ะ ฉันได้ลองใส่มันลงใน sqlfiddle แต่ฉันก็เลิกตั้งแต่ทุกคำถามที่ฉันพยายามเรียกใช้นอกจากการสร้างสคีมาจะหมดเวลา ฉันคิดออกว่าเพียงแค่ลบ "EXISTS" ก็ทำให้แบบสอบถามทำงานได้อย่างถูกต้องสำหรับฉัน
Clox

144

การสร้างคำตอบของ levik เพื่อรับ ID ของแถวที่ซ้ำกันที่คุณสามารถทำได้GROUP_CONCATหากเซิร์ฟเวอร์ของคุณรองรับ (จะเป็นการคืนรายการรหัส id ที่คั่นด้วยเครื่องหมายจุลภาค)

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

12
ตลอดเวลานี้โดยไม่ต้องรู้เกี่ยวกับ GROUP_CONCAT ()! มีประโยชน์มากมาก
aesede

ชื่นชมแมตต์จริงๆ สิ่งนี้มีประโยชน์อย่างแท้จริง! สำหรับผู้ที่พยายามอัปเดตใน phpmyadmin หากคุณปล่อย id ไว้พร้อมกับฟังก์ชั่นเช่นนี้: SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]จะเปิดใช้งานการแก้ไขแบบอินไลน์และควรอัพเดตแถวทั้งหมดที่เกี่ยวข้อง (หรืออย่างน้อยหนึ่งอันแรกที่ตรงกัน) แต่น่าเสียดายที่การแก้ไขสร้างข้อผิดพลาด Javascript ..
Armfoot

จากนั้นคุณจะคำนวณจำนวนรหัสที่ต้องทำซ้ำได้อย่างไร
CMCDragonkai

2
ฉันจะไม่ได้รับการจัดกลุ่มของ ID ทั้งหมดได้อย่างไร ด้วยค่าที่เกี่ยวข้องทั้งหมดในคอลัมน์ถัดจากพวกเขา ดังนั้นแทนที่จะจัดกลุ่มมันจะแสดง ID 1 และค่าของมัน ID 2 และค่าของมัน แม้ว่าจะมีค่าสำหรับ ID เหมือนกัน
MailBlade

1
คำตอบที่เป็นประโยชน์อย่างยิ่งนี้ควรจะอยู่ในอันดับต้น ๆ เพื่อให้คนอื่นเห็น ฉันจำได้ว่าฉันต้องเจ็บปวดมากแค่ไหนในการสร้างรายการเหล่านี้และมันก็มีอยู่ตลอดเวลาตามคำสั่ง ..
John

13

สมมติว่าตารางของคุณชื่อ 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

ข้อได้เปรียบของวิธีการนี้เหนือคำตอบข้างต้นคือให้คีย์


4
+1 เพราะสะดวก แม้ว่าแดกดันผลตัวเองมีซ้ำกัน (มันแสดงรายการและ b จากนั้น b และ a.)
Fabien Snauwaert

2
@FabienSnauwaert คุณสามารถกำจัดรายการที่ซ้ำกันบางรายการโดยการเปรียบเทียบน้อยกว่า (หรือมากกว่า)
Michael

@TechTravel คิดว่าคำตอบของคุณชัดเจนมากขอบคุณสำหรับสิ่งนั้น แต่ในตารางขนาดใหญ่ต้องใช้เวลาสักครู่ (ประมาณ 2mn บนตารางรายการมากกว่า 20,000 รายการ) และหลังจากแสดงผลลัพธ์ 25 รายการแรกหากฉันคลิกเพื่อแสดงรายการถัดไป phpmyadmin แสดงข้อผิดพลาด "# 1052 - คอลัมน์ 'id' ในส่วนคำสั่งนั้นไม่ชัดเจน "
bcag2

12
SELECT * 
FROM `dps` 
WHERE pid IN (SELECT pid FROM `dps` GROUP BY pid HAVING COUNT(pid)>1)

1
ไม่เพราะนี่อาจจะช้าที่สุด การเลือกย่อยช้าอย่างฉาวโฉ่เนื่องจากมันถูกเรียกใช้สำหรับทุกแถวที่ส่งคืน
Oddman

10

หากต้องการค้นหาจำนวนระเบียนที่ซ้ำกันในคอลัมน์ชื่อในพนักงานแบบสอบถามด้านล่างมีประโยชน์

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

10

เพื่อรับข้อมูลทั้งหมดที่มีการทำซ้ำฉันใช้สิ่งนี้:

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 = ข้อมูลซ้ำซ้อนที่คุณกำลังมองหา


อันนี้แสดงซ้ำกันในแถวของมันเอง นั่นคือสิ่งที่ฉันต้องการ ขอบคุณ
warmwhisky

8

ข้อความค้นหาสุดท้ายของฉันรวมคำตอบสองสามข้อไว้ที่นี่ซึ่งช่วย - รวมกลุ่มโดยนับ & GROUP_CONCAT

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

สิ่งนี้แสดงรหัสของทั้งสองตัวอย่าง (คั่นด้วยเครื่องหมายจุลภาค), บาร์โค้ดที่ฉันต้องการและจำนวนซ้ำ

เปลี่ยนตารางและคอลัมน์ตาม


8

ฉันไม่เห็นวิธีการเข้าร่วมใด ๆ ซึ่งมีประโยชน์หลายประการในแง่ของการทำซ้ำ

วิธีการนี้ให้ผลลัพธ์ที่แท้จริงสองเท่า

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

2
FYI - คุณจะต้อง 'เลือก somecol ที่แตกต่างกัน .. ' หากมีความเป็นไปได้ที่จะมีระเบียนที่ซ้ำกันมากกว่า 1 ระเบียนมิฉะนั้นผลลัพธ์จะมีข้อมูลซ้ำของแถวที่ซ้ำที่พบ
ดึง

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

แทนที่เมืองด้วยตารางของคุณ แทนที่ชื่อด้วยชื่อฟิลด์ของคุณ


7

การ@ maxyfc ของคำตอบต่อไปผมต้องการที่จะหาทุกแถวที่ได้กลับมาพร้อมกับค่าที่ซ้ำกันดังนั้นฉันสามารถแก้ไขได้ในMySQL Workbench :

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

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)

สิ่งที่ต้องการคือสิ่งที่แน่นอน! ที่นี่แบบสอบถามของฉันตรวจสอบ 3 เขตข้อมูลสำหรับรายการที่ซ้ำกัน:SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total>1
Kai Noack

4

ฉันชอบใช้ฟังก์ชั่นแบบมีหน้าต่าง (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


3
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

1
การทำเคียวรีย่อยเดียวกันซ้ำสองครั้งดูเหมือนว่าไม่มีประสิทธิภาพ
NobleUplift

3

ต่อไปนี้จะค้นหา 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


3
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)

2
SELECT DISTINCT a.email FROM `users` a LEFT JOIN `users` b ON a.email = b.email WHERE a.id != b.id;

1
น่าสังเกตว่านี่ช้าเกินไปเหลือเกินหรืออาจไม่เสร็จถ้าคอลัมน์ที่ถูกสอบถามไม่ได้ถูกทำดัชนี มิฉะนั้นผมก็สามารถที่จะเปลี่ยนa.emailไปa.*และได้รับรหัสทั้งหมดของแถวที่มีรายการที่ซ้ำกัน
NobleUplift

@NobleUplift คุณพูดถึงอะไร
Michael

@Michael เนื่องจากอายุสามปีนี้ฉันไม่สามารถทดสอบ MySQL รุ่นใดก็ได้ที่ฉันใช้อยู่ แต่ฉันลองใช้แบบสอบถามเดียวกันนี้ในฐานข้อมูลที่คอลัมน์ที่ฉันเลือกไม่มีดัชนีอยู่เลย ไม่กี่วินาทีให้เสร็จ เปลี่ยนเป็นSELECT DISTINCT a.*แก้ไขเกือบจะทันที
NobleUplift

@NobleUplift อ่าโอเค ฉันเข้าใจได้ว่ามันช้า ... ส่วนที่ฉันกังวลคือ "อาจไม่จบ"
Michael

@Michael ฉันจำไม่ได้ว่าตารางใดในระบบของฉันฉันต้องเรียกใช้แบบสอบถามนี้ แต่สำหรับรายการที่มีระเบียนไม่กี่ล้านรายการพวกเขาอาจจะเสร็จ แต่ในเวลาที่ใช้เวลานานมากที่ฉันยอมแพ้เมื่อเห็นว่า มันจะเสร็จจริง ๆ
NobleUplift

1

สำหรับการลบแถวที่ซ้ำกันที่มีหลายฟิลด์ให้ยกเลิกไปที่คีย์เฉพาะใหม่ซึ่งระบุไว้สำหรับแถวที่ต่างกันเท่านั้นจากนั้นใช้คำสั่ง "group by" เพื่อลบแถวที่ซ้ำกันด้วยคีย์เฉพาะใหม่ที่เหมือนกัน:

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;

คุณสามารถเพิ่มคำอธิบายได้ไหม?
Robert

ทำไมไม่ใช้CREATE TEMPORARY TABLE ...? คำอธิบายเล็ก ๆ ของการแก้ปัญหาของคุณจะดีมาก
maxhb

1

การบริจาคล่าช้ามาก ... ในกรณีที่มันช่วยให้ทุกคน waaaaaay ลงเส้น ... ฉันมีงานหาคู่ที่ตรงกันของธุรกรรม (อันที่จริงทั้งสองด้านของการถ่ายโอนระหว่างบัญชีกับบัญชี) ในแอพธนาคารเพื่อระบุว่าอันไหน คือ 'จาก' และ 'ถึง' สำหรับธุรกรรมการโอนเงินระหว่างบัญชีแต่ละรายการดังนั้นเราจึงได้ทำสิ่งนี้:

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ให้แถวที่มีการจับคู่ธุรกรรม (เช่นซ้ำกัน) แต่มันก็ให้รหัสธุรกรรมเดียวกันในสิ่งที่ตรงกันข้ามในครั้งที่สองที่ตรงกับคู่เดียวกันดังนั้นด้านนอกSELECTจะจัดกลุ่มตามรหัสธุรกรรมแรกซึ่งเสร็จสิ้นแล้ว โดยใช้LEASTและGREATESTเพื่อให้แน่ใจว่าทั้งสอง transactionid อยู่ในลำดับเดียวกันเสมอในผลลัพธ์ซึ่งทำให้ปลอดภัยGROUPโดยรายการแรกจึงกำจัดการแข่งขันที่ซ้ำกันทั้งหมด ขับรถผ่านเกือบหนึ่งล้านบันทึกและระบุการแข่งขันกว่า 12,000 รายการภายในเวลาเพียง 2 วินาที แน่นอนว่า transactionid เป็นดัชนีหลักซึ่งช่วยได้จริงๆ





โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.