MySQL टेबल पर डुप्लिकेट कैसे हटाएं?


158

मुझे टेबल DELETEपर निर्दिष्ट फ़ुट के लिए डुप्लिकेट की गई पंक्तियों की आवश्यकता है MySQL

मैं SQL क्वेरी के साथ ऐसा कैसे कर सकता हूं?

DELETE (DUPLICATED TITLES) FROM table WHERE SID = "1"

कुछ इस तरह, लेकिन मुझे नहीं पता कि यह कैसे करना है।


क्या आपको इसे केवल एक बार करने की आवश्यकता है या आपको इसे हर समय करने की आवश्यकता है?
बिली ओनेल

क्या डुप्लिकेट रिकॉर्ड वाले रिकॉर्ड्स में सभी समान डेटा हैं, या बाकी फ़ील्ड एक-दूसरे से अलग हैं? यदि आपके पास पहला विकल्प है तो आप सभी रिकॉर्डों को हटा सकते हैं लेकिन एक, यदि आपके पास दूसरा विकल्प है, तो आप यह कैसे निर्धारित कर रहे हैं कि आप कौन सा रिकॉर्ड रखना चाहते हैं?
rael_kid

@Lex पहला विकल्प। @ क्या मुझे इसे हर समय करने की आवश्यकता है।
अली डेमिरसी


1
MySQL के विभिन्न संस्करणों में बहुत सी चीज़ें यहाँ बदली हैं। यहां किसी भी समाधान के पथ को नीचे करने से पहले अपने MySQL संस्करण को ध्यान से देखें।
डेलटाबेल

जवाबों:


215

यह एक नई तालिका बनाने के बिना, जगह में डुप्लिकेट को हटाता है

ALTER IGNORE TABLE `table_name` ADD UNIQUE (title, SID)

नोट: केवल तभी अच्छा काम करता है जब सूचकांक स्मृति में फिट बैठता है


26
सूचना: यह सबसे पुराना डुप्लिकेट रिकॉर्ड रखेगा और नए लोगों को मिटा देगा। यदि आप नवीनतम रखना चाहते हैं तो आप ऐसा नहीं कर सकते ALTER IGNORE
हरलान डोबरेव

9
लगता है कि InnoDB के साथ काम नहीं करता है। मैं ALTER TABLE foo ENGINE MyISAMइसके चारों ओर काम करने के लिए भागा , इंजन को वापस बदल दिया।
मार्टिन

13
यह MySQL> 5.5 पर विफल हो सकता है, यदि ऐसा है तो "सेट सत्र old_alter_table = 1;" और "सेट सत्र old_alter_table = 0;" कथन के पहले और बाद में
chillitom


2
@delatbabel इसे अपदस्थ करने का कारण आपके द्वारा जुड़े पृष्ठ में दिया गया है।
बमर

133

मान लें कि आपके पास एक तालिका है employee, जिसमें निम्नलिखित कॉलम हैं:

employee (first_name, last_name, start_date)

डुप्लिकेट first_nameकॉलम वाली पंक्तियों को हटाने के लिए :

delete
from employee using employee,
    employee e1
where employee.id > e1.id
    and employee.first_name = e1.first_name  

1
शेष रिकॉर्ड में उसके डुप्लिकेट समूह में अधिकतम या न्यूनतम आईडी होगी?
फ्रोजन फ्लेम

शेष रिकॉर्ड में न्यूनतम आईडी होगी क्योंकि यह हटाए जाने की शर्त को पूरा नहीं करने वाला एकमात्र है
पाब्लो गुरेरो

1
employeeएक इंडेक्स मैच के लिए खुद के खिलाफ शामिल होने और एक >इंडेक्स पर एक चेक जैसे बड़े तालिकाओं के लिए धीमा होने जा रहा है। यह करने के लिए SELECT MAX(ID) FROM t GROUP BY uniqueऔर फिर JOINके एक सटीक मैच के IDलिए बेहतर नहीं होगा MAX(ID)?
ebyrob

1
बहुत बढ़िया जवाब! मेरा समय बचाया!
नेसर

56

सभी SID के लिए डुप्लिकेट हटाएं, केवल एक ही नहीं।

टेम्प टेबल के साथ

CREATE TABLE table_temp AS
SELECT * FROM table GROUP BY title, SID;

DROP TABLE table;
RENAME TABLE table_temp TO table;

चूंकि temp_tableहौसले से बनाया गया है इसलिए इसमें कोई इंडेक्स नहीं है। डुप्लिकेट को हटाने के बाद आपको उन्हें फिर से बनाना होगा। आप जाँच कर सकते हैं कि आपके पास तालिका में कौन से सूचकांक हैंSHOW INDEXES IN table

अस्थायी तालिका के बिना:

DELETE FROM `table` WHERE id IN (
  SELECT all_duplicates.id FROM (
    SELECT id FROM `table` WHERE (`title`, `SID`) IN (
      SELECT `title`, `SID` FROM `table` GROUP BY `title`, `SID` having count(*) > 1
    )
  ) AS all_duplicates 
  LEFT JOIN (
    SELECT id FROM `table` GROUP BY `title`, `SID` having count(*) > 1
  ) AS grouped_duplicates 
  ON all_duplicates.id = grouped_duplicates.id 
  WHERE grouped_duplicates.id IS NULL
)

4
ग्रुप-आईएनजी आपके द्वारा समूहित क्षेत्रों के मूल्यों के प्रत्येक संयोजन के लिए केवल एक परिणाम पंक्ति का उत्पादन करता है। इसलिए नकलची हटाए जाएंगे।
कामिल सजोट

4
मैं पहला रास्ता पसंद करता हूँ, यहाँ बहुत ज्यादा सुंदर है! : बी
AgelessEssence

1
@fiacre आप अस्थायी रूप से विदेशी कुंजी जांच को अक्षम कर सकते हैं: stackoverflow.com/questions/15501673/… आप अन्य पंक्तियों को संदर्भित करने वाली कुछ पंक्तियों को हटाते हुए भी जोखिम में पड़ सकते हैं, लेकिन आप यह नियंत्रित कर सकते हैं कि क्वेरी में फेरबदल करके कौन से रिकॉर्ड डेडअप तालिका में लिए गए हैं SELECT * FROM table GROUP BY title, SID;यह सब इस बात पर निर्भर करता है कि आप जानते हैं कि आप क्या कर रहे हैं।
कामिल स्ज़ोट

1
@ahnbizcad आप अस्थायी तालिका का उपयोग कर सकते हैं, लेकिन फिर आपको अस्थायी तालिका से नियमित तालिका में डेटा वापस कॉपी करना होगा। यदि आप वास्तविक तालिका का उपयोग करते हैं तो आप पुराने को डुप्लिकेट के साथ छोड़ सकते हैं और नए का नाम बदल सकते हैं, बिना डुप्लिकेट के पुराने के नाम पर।
कामिल सजोट

1
"बिना टेम्परेरी टेबल" की विधि, ओनली_FULL_GROUP_BY से निपटने के लिए सबसे अच्छे समाधान के सबसे करीब है, जो MySQL 5.7.5 में बदल गया है: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html मुझे यह मिल गया है "SELECT any_VALUE (id) AS id" के साथ "SELECT id" को बदलकर काम करने के लिए
delatbabel

53

MySQL-इन-प्लेस में डुप्लिकेट पंक्तियों को हटाना, (मान लें कि आपके पास टाइमस्टैम्प कर्नल को सॉर्ट करने के लिए) walkthrough:

तालिका बनाएँ और कुछ पंक्तियाँ डालें:

create table penguins(foo int, bar varchar(15), baz datetime);
insert into penguins values(1, 'skipper', now());
insert into penguins values(1, 'skipper', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(3, 'kowalski', now());
insert into penguins values(4, 'rico', now());
select * from penguins;
    +------+----------+---------------------+
    | foo  | bar      | baz                 |
    +------+----------+---------------------+
    |    1 | skipper  | 2014-08-25 14:21:54 |
    |    1 | skipper  | 2014-08-25 14:21:59 |
    |    3 | kowalski | 2014-08-25 14:22:09 |
    |    3 | kowalski | 2014-08-25 14:22:13 |
    |    3 | kowalski | 2014-08-25 14:22:15 |
    |    4 | rico     | 2014-08-25 14:22:22 |
    +------+----------+---------------------+
6 rows in set (0.00 sec)

जगह में डुप्लिकेट निकालें:

delete a
    from penguins a
    left join(
    select max(baz) maxtimestamp, foo, bar
    from penguins
    group by foo, bar) b
    on a.baz = maxtimestamp and
    a.foo = b.foo and
    a.bar = b.bar
    where b.maxtimestamp IS NULL;
Query OK, 3 rows affected (0.01 sec)
select * from penguins;
+------+----------+---------------------+
| foo  | bar      | baz                 |
+------+----------+---------------------+
|    1 | skipper  | 2014-08-25 14:21:59 |
|    3 | kowalski | 2014-08-25 14:22:15 |
|    4 | rico     | 2014-08-25 14:22:22 |
+------+----------+---------------------+
3 rows in set (0.00 sec)

आप कर रहे हैं, डुप्लिकेट पंक्तियों को हटा दिया जाता है, टाइमस्टैम्प द्वारा पिछले एक रखा जाता है।

बिना टाइमस्टैम्प या अनूठे कॉलम के आप के लिए।

आपके पास timestampसॉर्ट करने के लिए एक या एक अद्वितीय सूचकांक कॉलम नहीं है? आप अधोगति की स्थिति में रह रहे हैं। डुप्लिकेट पंक्तियों को हटाने के लिए आपको अतिरिक्त चरण करने होंगे।

पेंगुइन तालिका बनाएँ और कुछ पंक्तियाँ जोड़ें

create table penguins(foo int, bar varchar(15)); 
insert into penguins values(1, 'skipper'); 
insert into penguins values(1, 'skipper'); 
insert into penguins values(3, 'kowalski'); 
insert into penguins values(3, 'kowalski'); 
insert into penguins values(3, 'kowalski'); 
insert into penguins values(4, 'rico'); 
select * from penguins; 
    # +------+----------+ 
    # | foo  | bar      | 
    # +------+----------+ 
    # |    1 | skipper  | 
    # |    1 | skipper  | 
    # |    3 | kowalski | 
    # |    3 | kowalski | 
    # |    3 | kowalski | 
    # |    4 | rico     | 
    # +------+----------+ 

पहली तालिका का एक क्लोन बनाएं और उसमें कॉपी करें।

drop table if exists penguins_copy; 
create table penguins_copy as ( SELECT foo, bar FROM penguins );  

#add an autoincrementing primary key: 
ALTER TABLE penguins_copy ADD moo int AUTO_INCREMENT PRIMARY KEY first; 

select * from penguins_copy; 
    # +-----+------+----------+ 
    # | moo | foo  | bar      | 
    # +-----+------+----------+ 
    # |   1 |    1 | skipper  | 
    # |   2 |    1 | skipper  | 
    # |   3 |    3 | kowalski | 
    # |   4 |    3 | kowalski | 
    # |   5 |    3 | kowalski | 
    # |   6 |    4 | rico     | 
    # +-----+------+----------+ 

अधिकतम समुच्चय नए moo सूचकांक पर संचालित होता है:

delete a from penguins_copy a left join( 
    select max(moo) myindex, foo, bar 
    from penguins_copy 
    group by foo, bar) b 
    on a.moo = b.myindex and 
    a.foo = b.foo and 
    a.bar = b.bar 
    where b.myindex IS NULL; 

#drop the extra column on the copied table 
alter table penguins_copy drop moo; 
select * from penguins_copy; 

#drop the first table and put the copy table back: 
drop table penguins; 
create table penguins select * from penguins_copy; 

निरीक्षण करें और सफाई करें

drop table penguins_copy; 
select * from penguins;
+------+----------+ 
| foo  | bar      | 
+------+----------+ 
|    1 | skipper  | 
|    3 | kowalski | 
|    4 | rico     | 
+------+----------+ 
    Elapsed: 1458.359 milliseconds 

वह बड़ा SQL डिलीट स्टेटमेंट क्या कर रहा है?

उपनाम 'ए' के ​​साथ टेबल पेंग्विन को छोड़ दिया गया है, जिसे टेबल पेंग्विन के उपसमूह में शामिल किया गया है, जिसे उपनाम 'बी' कहा जाता है। दाहिने हाथ की मेज 'बी' जो कि एक सबसेट है, कॉलम फू और बार द्वारा समूहीकृत अधिकतम टाइमस्टैम्प [या अधिकतम म्यू] पाता है। यह बाएं हाथ की मेज 'a' से मेल खाता है। (फू, बार, बाज) बाईं ओर की मेज में हर पंक्ति है। दाहिने हाथ की उप-कक्षा 'बी' में एक (मैक्सिममस्टैम्प, फू, बार) है जो केवल उसी पर छोड़ दिया जाता है जो कि अधिकतम है।

हर पंक्ति जो कि अधिकतम नहीं है, उसमें NULL का अधिकतम मैक्सिममैंप है। उन NULL पंक्तियों पर फ़िल्टर करें और आपके पास फू और बार द्वारा समूहीकृत सभी पंक्तियों का एक सेट है जो नवीनतम टाइमस्टैम्प बाज नहीं है। उन लोगों को हटा दें।

इसे चलाने से पहले तालिका का बैकअप बना लें।

इस समस्या को इस तालिका पर फिर से होने से रोकें:

यदि आपको यह काम करने के लिए मिला, और इसने आपकी "डुप्लीकेट पंक्ति" को आग लगा दी। महान। अब अधिक डुप्लिकेट को पहली जगह में जोड़ने से रोकने के लिए अपनी तालिका (उन दो स्तंभों पर) पर एक नई समग्र अद्वितीय कुंजी परिभाषित करें।

एक अच्छी प्रतिरक्षा प्रणाली की तरह, खराब पंक्तियों को भी डालने के समय मेज पर नहीं जाने देना चाहिए। बाद में डुप्लिकेट जोड़ने वाले उन सभी कार्यक्रमों पर उनके विरोध को प्रसारित किया जाएगा, और जब आप उन्हें ठीक करेंगे, तो यह मुद्दा फिर कभी नहीं आएगा।


6
मेडागास्कर संदर्भ के लिए विशुद्ध रूप से दर!
माइकल विगिन्स

1
यह एक महान जवाब है, और महान सुझाव के बाद से रेटेड, धन्यवाद एरिक वहाँ किसी भी अन्य जवाब से बेहतर काम किया।
जोहान

4
नोट: यदि आपकी तालिका में एक ऑटो इंक्रीमेंट IDकॉलम है, तो ONक्लॉज को केवल IDकॉलम से मिलान करने की आवश्यकता है , और कुछ नहीं।
इब्रोब

1
मुझे विस्तृत विवरण पसंद है लेकिन ... अगर मैं सही ढंग से समझूं, तो यह उत्तर रिकॉर्ड के बीच अंतर करने के लिए टाइमस्टैम्प का उपयोग करता है। इस अर्थ में, रिकॉर्ड डुप्लिकेट नहीं हैं। क्या होगा अगर आपके पास रिकॉर्ड के बीच अंतर करने के लिए टाइमस्टैम्प नहीं है यानी सभी कॉल 2 या अधिक रिकॉर्ड के लिए समान हैं?
23

1
@RscRsc यदि आपके पास अधिकतम एग्रीगेट लगाने के लिए टाइमस्टैम्प कॉलम या यूनिक इंडेक्स नहीं है, तो ऐसा लगता है कि आपको टेबल को डुप्लिकेट करना है, एक यूनिक इंडेक्स जोड़ना है, डिलीट स्टेटमेंट को लागू करना है, फिर कॉपी किए गए टेबल को मूल में बदलें। । मैंने इन निर्देशों को प्रतिबिंबित करने के लिए उत्तर बदल दिया।
एरिक लेसचिंस्की

16

इस मुद्दे पर खुद को चलाने के बाद, एक विशाल डेटाबेस पर, मैं किसी भी अन्य उत्तर के प्रदर्शन से पूरी तरह प्रभावित नहीं हुआ। मैं केवल नवीनतम डुप्लिकेट पंक्ति रखना चाहता हूं, और बाकी को हटाना चाहता हूं।

एक-क्वेरी स्टेटमेंट में, एक अस्थायी तालिका के बिना, इसने मेरे लिए सबसे अच्छा काम किया,

DELETE e.*
FROM employee e
WHERE id IN
 (SELECT id
   FROM (SELECT MIN(id) as id
          FROM employee e2
          GROUP BY first_name, last_name
          HAVING COUNT(*) > 1) x);

एकमात्र चेतावनी यह है कि मुझे क्वेरी को कई बार चलाना है, लेकिन इसके साथ ही, मैंने पाया कि यह अन्य विकल्पों की तुलना में मेरे लिए बेहतर काम करती है।


1
व्यावहारिक समाधान! मेरे लिए काम किया - एक 2m + पंक्ति innodb तालिका के लिए लगभग 20s। एक बार जब मैंने इसे कुछ बार उपयोग किया और उच्च संख्या में डुप्लिकेट के साथ कुछ अपराधियों के लिए नीचे था, तो मैन्युअल रूप से काम समाप्त कर दिया।
ट्रॉय रे

1
एक झाडू में मेरे लिए काम किया, कमाल!
मुरा

इसे कई बार निष्पादित किया जाना चाहिए यदि किसी भी कॉलम के लिए डुप्लिकेट 2x से अधिक हैं
पेतेआर

@PayteR के जवाब में कहा गया है, "एकमात्र चेतावनी यह है कि मुझे कई बार क्वेरी को चलाना होगा"
सईदर्स

13

यह हमेशा मेरे लिए काम करता है:

CREATE TABLE NoDupeTable LIKE DupeTable; 
INSERT NoDupeTable SELECT * FROM DupeTable group by CommonField1,CommonFieldN;

जो प्रत्येक डूप पर सबसे कम आईडी रखता है और बाकी के नॉन-ड्यूप रिकॉर्ड में।

मैंने निम्नलिखित कार्य करने के लिए भी लिया है ताकि हटाने के बाद अब कोई समस्या न हो:

CREATE TABLE NoDupeTable LIKE DupeTable; 
Alter table NoDupeTable Add Unique `Unique` (CommonField1,CommonField2);
INSERT IGNORE NoDupeTable SELECT * FROM DupeTable;

दूसरे शब्दों में, मैं पहली तालिका का एक डुप्लिकेट बनाता हूं, उन फ़ील्ड्स पर एक अद्वितीय अनुक्रमणिका जोड़ें, Insert IGNOREजिनके बारे में मुझे डुप्लिकेट नहीं चाहिए, और फिर एक ऐसा करें जिसमें एक सामान्य के रूप में असफल न होने का लाभ Insertपहली बार जोड़ने की कोशिश की गई हो दो क्षेत्रों के आधार पर एक डुप्लिकेट रिकॉर्ड और ऐसे किसी भी रिकॉर्ड को अनदेखा करता है।

एफडब्ल्यूडी को आगे बढ़ाते हुए उन दो क्षेत्रों के आधार पर कोई भी डुप्लिकेट रिकॉर्ड बनाना असंभव हो जाता है।


1
आप एक की जरूरत नहीं होगी ORDER BYमें SELECTयकीन है कि जो रिकॉर्ड वास्तव में यह बनाता है के लिए खत्म होने की NoDupeTable?
ebyrob

@ebyrob मेरा मानना ​​है कि जब तक अन्यथा यह निर्देश नहीं दिया गया है कि यह अन्य मानदंडों के अभाव में सबसे कम आईडी का चयन करेगा। निश्चित रूप से ORDER by ID Ascचोट नहीं पहुंचा सकता, इसलिए मैं अपना उत्तर संपादित नहीं करूंगा।
user3649739

@ebyrob माफ करना मेरी बुर। इस क्रम में मेरे ज्ञान का चयन करने से काम नहीं चलेगा। चयन के अंत में एक ऑर्डर केवल प्रत्येक जोड़ी में मिली सबसे कम आईडी द्वारा पाए गए डुप्लिकेट का आदेश देगा। वैकल्पिक रूप से आप एक Select Max(ID)और फिर कर सकते थे, Order by Max(ID)लेकिन वह सब कुछ सम्मिलित करने के क्रम को उलट देगा। उच्चतम आईडी को हथियाने के लिए मुझे विश्वास होगा कि आप अधिक जटिल चयन में शामिल होंगे, चाहे आप ऊपर के आदेश को कैसे भी मानें, निचले आईडी से फ़ील्ड मान हथियाना होगा।
user3649739

वास्तव में, यह निश्चित नहीं है कि मैं किस क्रम से सोच रहा था। आप निश्चित रूप से चाहते हैं MAX(ID)या MIN(ID)और बजाय स्तंभ नाम *में SELECT FROM DupeTableहालांकि, अन्यथा आप बस में से एक मिल जाएगा ID'बेतरतीब ढंग से है। वास्तव में, कई SQL और यहां तक ​​कि MySQL सख्त को GROUP BYक्लॉज में निर्दिष्ट प्रत्येक कॉलम पर एक कुल फ़ंक्शन को कॉल करने की आवश्यकता होती है ।
ebyrob

@ebyrob अधिकतम (आईडी) मिन (आईडी) का परीक्षण करने पर मैक्स या माइंड रिकॉर्ड की आईडी को छोड़कर कुछ भी नहीं करते हैं। प्रत्येक मामले में एक ही रिकॉर्ड पकड़ लेता है। इसलिए यदि मेरे पास फ़ील्ड्स ID,First,Last,Notesऔर रिकॉर्ड्स के साथ दो रिकॉर्ड हैं 1,Bob,Smith,NULLऔर 2,Bob,Smith,Arrearsफिर SELECT *Max(ID), First,Last,Notes FROM DupeTable group by First,Lastदोनों एक ही रिकॉर्ड को वापस कर देंगे, 1, एक अलग आईडी के साथ। मैक्स (आईडी) वापस आ जाएगी 2,Bob,Smith,NULLऔर मिन (आईडी) वापस आ जाएगी 1,Bob,Smith,NULL। नोटों में `एरियर्स 'के साथ दूसरा रिकॉर्ड प्राप्त करने के लिए मुझे शामिल होने वाले एक विश्वास की आवश्यकता है।
user3649739

7

निम्नलिखित सभी तालिकाओं के लिए काम करता है

CREATE TABLE `noDup` LIKE `Dup` ;
INSERT `noDup` SELECT DISTINCT * FROM `Dup` ;
DROP TABLE `Dup` ;
ALTER TABLE `noDup` RENAME `Dup` ;

6

यहाँ एक सरल जवाब है:

delete a from target_table a left JOIN (select max(id_field) as id, field_being_repeated  
    from target_table GROUP BY field_being_repeated) b 
    on a.field_being_repeated = b.field_being_repeated
      and a.id_field = b.id_field
    where b.id_field is null;

इसका एक अच्छा जवाब, एक छोटी सी गलती को छोड़करand a.id_field = b.id
विक्रांत गोयल

LEFT JOINकरने के लिए bकेवल तुलना करने के लिए की जरूरत है b.id= a.id_fieldसंभालने field_idके लिए एक अनूठा ऑटो वेतन वृद्धि आईडी है। ऐसा a.field_being_repeated = b.field_being_repeatedविलोम है। (यह भी b.id_fieldइस क्वेरी में मौजूद नहीं है b.id
ebyrob

6

मेरे लिए यह काम पुराने रिकॉर्ड को हटाने के लिए है:

delete from table where id in 
(select min(e.id)
    from (select * from table) e 
    group by column1, column2
    having count(*) > 1
); 

नए रिकॉर्ड हटाने के लिए आप मिन (e.id) को अधिकतम (e.id) में बदल सकते हैं।


5
delete p from 
product p
inner join (
    select max(id) as id, url from product 
    group by url 
    having count(*) > 1
) unik on unik.url = p.url and unik.id != p.id;

1
मैंने पाया कि ऊपर वाले लोगों की तुलना में कहीं अधिक बेहतर समाधान
क्रिश्चियन बटजके

5

मैं वर्नर के समाधान खोजने के ऊपर सबसे अधिक सुविधाजनक है क्योंकि यह एक प्राथमिक कुंजी की उपस्थिति की परवाह किए बिना काम करता है, टेबल के साथ गड़बड़ नहीं है, भविष्य प्रूफ सादा एसक्यूएल का उपयोग करता है, बहुत समझा जा सकता है किया जाना है।

जैसा कि मैंने अपनी टिप्पणी में कहा है, उस समाधान को ठीक से समझाया नहीं गया है। तो यह मेरा है, इसके आधार पर।

1) एक नया बूलियन कॉलम जोड़ें

alter table mytable add tokeep boolean;

2) डुप्लिकेटेड कॉलम और नए कॉलम पर एक बाधा जोड़ें

alter table mytable add constraint preventdupe unique (mycol1, mycol2, tokeep);

3) बूलियन कॉलम को सही पर सेट करें। यह नए अवरोध के कारण केवल एक अनुलिपि पंक्तियों पर सफल होगा

update ignore mytable set tokeep = true;

4) उन पंक्तियों को हटा दें जिन्हें टोल के रूप में चिह्नित नहीं किया गया है

delete from mytable where tokeep is null;

5) जोड़े गए कॉलम को छोड़ें

alter table mytable drop tokeep;

मेरा सुझाव है कि आप अपने द्वारा जोड़े गए अवरोध को बनाए रखें, ताकि भविष्य में नए डुप्लिकेट को रोका जा सके।


4

यह प्रक्रिया अंतिम डुप्लिकेट रखते हुए सभी डुप्लिकेट (incl गुणक) को एक तालिका में हटा देगी। यह प्रत्येक समूह में पिछले रिकॉर्ड को पुनः प्राप्त करने का एक विस्तार है

आशा है कि यह किसी के लिए उपयोगी है।

DROP TABLE IF EXISTS UniqueIDs;
CREATE Temporary table UniqueIDs (id Int(11));

INSERT INTO UniqueIDs
    (SELECT T1.ID FROM Table T1 LEFT JOIN Table T2 ON
    (T1.Field1 = T2.Field1 AND T1.Field2 = T2.Field2 #Comparison Fields 
    AND T1.ID < T2.ID)
    WHERE T2.ID IS NULL);

DELETE FROM Table WHERE id NOT IN (SELECT ID FROM UniqueIDs);

4

एक और आसान तरीका ... UPDATE IGNORE का उपयोग:

U को एक या अधिक कॉलम (टाइप इंडेक्स) पर एक इंडेक्स का उपयोग करना होगा। एक नया अस्थायी संदर्भ कॉलम बनाएं (इंडेक्स का हिस्सा नहीं)। इस कॉलम में, आप इसे अनदेखा खंड के साथ अद्यतन करके uniques चिह्नित करते हैं। क्रमशः:

प्राचीन वस्तुओं को चिह्नित करने के लिए एक अस्थायी संदर्भ कॉलम जोड़ें:

ALTER TABLE `yourtable` ADD `unique` VARCHAR(3) NOT NULL AFTER `lastcolname`;

=> यह आपकी तालिका में एक कॉलम जोड़ देगा।

तालिका को अपडेट करें, सब कुछ अद्वितीय के रूप में चिह्नित करने का प्रयास करें, लेकिन डुप्लिकेट कुंजी जारी करने के कारण संभावित त्रुटियों को अनदेखा करें (रिकॉर्ड छोड़ दिया जाएगा):

UPDATE IGNORE `yourtable` SET `unique` = 'Yes' WHERE 1;

=> आप पाएंगे कि आपके डुप्लिकेट रिकॉर्ड अद्वितीय = 'हां' के रूप में चिह्नित नहीं किए जाएंगे, दूसरे शब्दों में डुप्लिकेट रिकॉर्ड के प्रत्येक सेट में से केवल एक को अद्वितीय के रूप में चिह्नित किया जाएगा।

वह सब कुछ हटा दें जो अद्वितीय नहीं है:

DELETE * FROM `yourtable` WHERE `unique` <> 'Yes';

=> यह सभी डुप्लिकेट रिकॉर्ड को हटा देगा।

कॉलम ड्रॉप करें ...

ALTER TABLE `yourtable` DROP `unique`;

मुझे लगता है कि यह सबसे अच्छा समाधान है क्योंकि यह तालिकाओं के साथ खिलवाड़ नहीं करता है और यह सादे सरल वर्ग का उपयोग करता है। केवल एक चीज को स्पष्ट किया जाना चाहिए: uniqueस्तंभ को एक अद्वितीय बाधा के साथ जोड़ा जाना चाहिए जो वर्तमान में दोहराए गए स्तंभों के साथ है, अन्यथा पूरी चीज काम नहीं करती है क्योंकि SET unique= 'Yes' कभी भी विफल नहीं होगा।
xtian

यह भी जान लें कि uniqueयह एक mysql कीवर्ड है। तो यह backticks है (के रूप में पहले से ही सही ढंग से प्रदर्शित)। कॉलम के लिए दूसरे शब्द का उपयोग करना अधिक सुविधाजनक हो सकता है।
टॉर्स्टन

2

MySQL टेबल पर डुप्लिकेट को हटाना एक सामान्य मुद्दा है, जो आमतौर पर विशिष्ट आवश्यकताओं के साथ आता है। यदि किसी को दिलचस्पी है, तो यहां ( MySQL में डुप्लिकेट पंक्तियां निकालें ) मैं समझाता हूं कि कैसे एक विश्वसनीय और तेज़ तरीके से MySQL डुप्लिकेट को हटाने के लिए एक अस्थायी तालिका का उपयोग करें, बड़े डेटा स्रोतों (विभिन्न उपयोग मामलों के लिए उदाहरण के साथ) को संभालने के लिए भी मान्य है।

अली , आपके मामले में, आप कुछ इस तरह से चला सकते हैं:

-- create a new temporary table
CREATE TABLE tmp_table1 LIKE table1;

-- add a unique constraint    
ALTER TABLE tmp_table1 ADD UNIQUE(sid, title);

-- scan over the table to insert entries
INSERT IGNORE INTO tmp_table1 SELECT * FROM table1 ORDER BY sid;

-- rename tables
RENAME TABLE table1 TO backup_table1, tmp_table1 TO table1;

0
delete from `table` where `table`.`SID` in 
    (
    select t.SID from table t join table t1 on t.title = t1.title  where t.SID > t1.SID
)

यह MySQL के कुछ विन्यास और संस्करणों पर SQL त्रुटि (1093) उत्पन्न करता है।
ebyrob

0

प्रेम @ एरिक का जवाब है, लेकिन यह काम नहीं करता है यदि आपके पास वास्तव में बड़ी तालिका है (मैं The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET MAX_JOIN_SIZE=# if the SELECT is okayइसे चलाने की कोशिश कर रहा हूं)। इसलिए मैंने सम्मिलित क्वेरी को केवल डुप्लिकेट पंक्तियों पर विचार करने के लिए सीमित कर दिया और मैं इसके साथ समाप्त हुआ:

DELETE a FROM penguins a
    LEFT JOIN (SELECT COUNT(baz) AS num, MIN(baz) AS keepBaz, foo
        FROM penguins
        GROUP BY deviceId HAVING num > 1) b
        ON a.baz != b.keepBaz
        AND a.foo = b.foo
    WHERE b.foo IS NOT NULL

इस मामले में WHASS क्लॉज MySQL को किसी भी पंक्ति को अनदेखा करने की अनुमति देता है जिसमें कोई डुप्लिकेट नहीं है और यह भी अनदेखा करेगा कि क्या यह डुप्लिकेट का पहला उदाहरण है इसलिए केवल बाद के डुप्लिकेट को अनदेखा किया जाएगा। बदलें MIN(baz)करने के लिए MAX(baz)पहले के बजाय पिछले उदाहरण रखने के लिए।


0

यह बड़े तालिकाओं के लिए काम करता है:

 CREATE Temporary table duplicates AS select max(id) as id, url from links group by url having count(*) > 1;

 DELETE l from links l inner join duplicates ld on ld.id = l.id WHERE ld.id IS NOT NULL;

के लिए सबसे पुराने परिवर्तन को हटाने के max(id)लिएmin(id)


0

यह यहां कॉलम column_nameको एक प्राथमिक कुंजी में बनाएगा , और इस बीच सभी त्रुटियों को अनदेखा करेगा। तो यह डुप्लिकेट मान वाली पंक्तियों को हटा देगा column_name

ALTER IGNORE TABLE `table_name` ADD PRIMARY KEY (`column_name`);

जैसा कि पिछले उत्तर की टिप्पणियों में बताया गया है, यह अब 5.7 में काम नहीं करता है।
बरमार

0

मुझे लगता है कि यह मूल रूप से तालिका की प्रतिलिपि बनाने और इसे खाली करने से काम करेगा, फिर इसमें केवल अलग-अलग मान डालेंगे, लेकिन कृपया इसे बड़ी मात्रा में डेटा पर करने से पहले इसे दोबारा जांचें।

आपकी टेबल की कार्बन कॉपी बनाता है

बनाने की तालिका temp_table जैसे oldtablename; temt_table select * oldtablename से डालें;

अपनी मूल तालिका को खाली करता है

DELETE * पुरानेबेलनाम से;

प्रतिलिपि की गई तालिका से वापस अपनी मूल तालिका में सभी भिन्न मानों की प्रतिलिपि बनाता है

पहले नाम, lastname, dob द्वारा temp_table group से INSERT oldtablename Select * करें

अपनी अस्थायी तालिका हटाता है।

ड्रॉप टेबल temp_table

आपको उन एलएलएल फ़ील्ड्स के समूह बनाने की ज़रूरत है जिन्हें आप अलग रखना चाहते हैं।


0
DELETE T2
FROM   table_name T1
JOIN   same_table_name T2 ON (T1.title = T2.title AND T1.ID <> T2.ID)

यह आपके अनुरोध पर काम नहीं करता है, कृपया आप इसे सुधार सकते हैं?
समीर गुइडरक

0

यहां बताया गया है कि मैं आमतौर पर डुप्लिकेट को कैसे समाप्त करता हूं

  1. एक अस्थायी कॉलम जोड़ें, इसे जो चाहें नाम दें (मैं सक्रिय रूप में संदर्भित करूंगा)
  2. उन फ़ील्ड्स द्वारा समूह, जिनके बारे में आपको लगता है कि उन्हें डुप्लिकेट नहीं होना चाहिए और उनके सक्रिय को 1 पर सेट करना है, उस कॉलम के लिए केवल एक डुप्लिकेट मान (डुप्लिकेट का चयन नहीं करेगा) का चयन करके समूहीकरण करना
  3. सक्रिय शून्य वाले को हटाएं
  4. ड्रॉप कॉलम सक्रिय
  5. वैकल्पिक रूप से (यदि आपके उद्देश्यों के लिए फिट बैठता है), उन कॉलमों के लिए अद्वितीय सूचकांक जोड़ें, जिनमें फिर से डुप्लिकेट न हों

-2

तुम बस (और "साफ" सूची का चयन करने के एक अलग खंड इस्तेमाल कर सकते हैं यहाँ कि कैसे करना है पर एक बहुत ही आसान उदाहरण है)।


कैसे इस सवाल का जवाब देता है? DISTINCTआपके द्वारा डुप्लिकेट के बारे में किसी भी जानकारी का उपयोग करने से आप पहले स्थान पर हो सकते हैं। क्या आप इसका उपयोग करके डुप्लिकेट को हटाने का एक तरीका दिखा सकते हैं?
luk2302

-3

यदि आप उन्हें गिनते हैं, तो यह काम कर सकता है, और फिर अपनी डिलीट क्वेरी की सीमा को केवल एक जोड़ सकता है?

उदाहरण के लिए, यदि आपके पास दो या अधिक हैं, तो अपनी क्वेरी इस तरह लिखें:

DELETE FROM table WHERE SID = 1 LIMIT 1;

-5

आपकी तालिका से डुप्लिकेट डेटा हटाते समय कुछ बुनियादी कदम हैं:

  • अपनी तालिका का बैक अप लें!
  • डुप्लीकेट पंक्तियों का पता लगाएं
  • डुप्लिकेट पंक्तियाँ निकालें

यहाँ पूर्ण ट्यूटोरियल है: https://blog.teamsql.io/de हटाना-duplicate-data- 3541485343473


यह काम करता है अगर केवल अद्वितीय आईडी अलग है। एएर सादेस बेंजर्सिज आईडी फारकली इस डे बु इ यार मार
एंड्रयू

डिफ़ॉल्ट रूप से यहाँ वर्णित विधि MySQL संस्करणों> 5.7.5 के लिए काम नहीं करती है। इसका कारण ONLY_FULL_GROUP_BY की हैंडलिंग है। यहां देखें: dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
delatbabel
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.