MySQL में डुप्लिकेट पंक्तियाँ निकालें


375

मेरे पास निम्नलिखित फ़ील्ड के साथ एक तालिका है:

id (Unique)
url (Unique)
title
company
site_id

अब, मुझे समान पंक्तियों को हटाने की आवश्यकता है title, company and site_id। इसे करने का एक तरीका स्क्रिप्ट के साथ निम्नलिखित SQL का उपयोग करना होगा ( PHP):

SELECT title, site_id, location, id, count( * ) 
FROM jobs
GROUP BY site_id, company, title, location
HAVING count( * ) >1

इस क्वेरी को चलाने के बाद, मैं सर्वर साइड स्क्रिप्ट का उपयोग करके डुप्लिकेट हटा सकता हूं।

लेकिन, मैं जानना चाहता हूं कि क्या यह केवल SQL क्वेरी का उपयोग करके किया जा सकता है।


1
त्वरित प्रश्न: क्या हमेशा चाहते हैं कि डुप्लिकेट (शीर्षक, कंपनी, साइट_आईडी) मौजूद न हो? यदि हां, तो मैं अद्वितीय होने के लिए शीर्षक, कंपनी और साइट_आईडी लागू करने के लिए डेटाबेस में एक बाधा स्थापित करूँगा। इसका मतलब है कि आपको सफाई प्रक्रिया की आवश्यकता नहीं होगी। और यह केवल SQL की एक लाइन लेता है।
जे। पोलर

1
कृपया स्टैकओवरफ़्लो के इस लिंक को देखें । यह मेरे लिए एक आकर्षण के रूप में काम करता है।

मैं इस समाधान की सिफारिश कर सकता हूं (दूसरे धागे में पोस्ट किया गया): stackoverflow.com/a/4685232/195835
सिमोन ईस्ट

जवाबों:


607

ऐसा करने का एक बहुत आसान तरीका है एक जोड़ना UNIQUE 3 कॉलम पर इंडेक्स । जब आप ALTERस्टेटमेंट लिखते हैं , तो IGNOREकीवर्ड शामिल करें । इस तरह:

ALTER IGNORE TABLE jobs
ADD UNIQUE INDEX idx_name (site_id, title, company);

यह सभी डुप्लिकेट पंक्तियों को छोड़ देगा। एक अतिरिक्त लाभ के रूप में, भविष्य INSERTsजो डुप्लिकेट हैं, वह त्रुटि देगा। हमेशा की तरह, आप कुछ इस तरह से चलाने से पहले बैकअप लेना चाहते हैं ...


8
दिलचस्प है , लेकिन उन डुप्लिकेट्स को हटाने के लिए IGNORE क्लॉज की धारणा एक चिंता है जो जरूरतों से मेल नहीं खाती है। गलत मानों को निकटतम स्वीकार्य मैच ध्वनि से काट दिया जा रहा है जो आपके लिए अच्छा है?
OMG पॉनीज़

75
सिर्फ रिकॉर्ड के लिए यदि आपका InnoDB का उपयोग कर रहा है तो आपके पास इसके साथ कोई समस्या हो सकती है, InnoDB डेटाबेस के साथ ALTER IGNORE TABLE का उपयोग करने के बारे में एक ज्ञात बग है।
डार्कमंटिस

27
उपर्युक्त बग @DarkMantis को संदर्भित किया गया और इसका समाधान है
जॉर्डन आर्सेनो

42
InnoDB तालिकाओं के लिए निम्नलिखित क्वेरी को पहले निष्पादित करें:set session old_alter_table=1;
shock_one


180

यदि आप कॉलम के गुणों को बदलना नहीं चाहते हैं, तो आप नीचे दिए गए क्वेरी का उपयोग कर सकते हैं।

चूंकि आपके पास एक कॉलम है जिसमें अद्वितीय आईडी (जैसे, auto_incrementकॉलम) हैं, आप इसका उपयोग डुप्लिकेट को निकालने के लिए कर सकते हैं:

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND (`a`.`title` = `b`.`title` OR `a`.`title` IS NULL AND `b`.`title` IS NULL)
    AND (`a`.`company` = `b`.`company` OR `a`.`company` IS NULL AND `b`.`company` IS NULL)
    AND (`a`.`site_id` = `b`.`site_id` OR `a`.`site_id` IS NULL AND `b`.`site_id` IS NULL);

MySQL में, आप इसे NULL-safe समान ऑपरेटर (उर्फ "स्पेसशिप ऑपरेटर" ) के साथ और भी सरल बना सकते हैं :

DELETE `a`
FROM
    `jobs` AS `a`,
    `jobs` AS `b`
WHERE
    -- IMPORTANT: Ensures one version remains
    -- Change "ID" to your unique column's name
    `a`.`ID` < `b`.`ID`

    -- Any duplicates you want to check for
    AND `a`.`title` <=> `b`.`title`
    AND `a`.`company` <=> `b`.`company`
    AND `a`.`site_id` <=> `b`.`site_id`;

3
यह समाधान ठीक से काम नहीं कर रहा है, मैंने कुछ डुप्लिकेट रिकॉर्ड बनाने की कोशिश की और यह कुछ ऐसा करता है (प्रभावित 20 पंक्तियाँ) लेकिन अगर आप इसे फिर से चलाते हैं तो यह आपको (4 पंक्तियों को प्रभावित) दिखाएगा और इसी तरह जब तक आप नहीं पहुँचते (0 पंक्तियाँ प्रभावित) जो थोड़े संदिग्ध है और यहाँ वही है जो मेरे लिए सबसे अच्छा काम करता है, यह लगभग एक जैसा है, लेकिन यह एक रन में काम करता है, मैंने समाधान संपादित किया
नासिम

1
@ नासिम: आपको इस जवाब से कुछ अलग करना चाहिए क्योंकि यह मेरे लिए (MySQL में) पूरी तरह से काम करता है।
लॉरेंस डॉल

3
किसी के लिए जो मेरी तरह भ्रमित था, NULL तुलना की शर्तों की आवश्यकता है क्योंकि NULL MySQL में NULL के बराबर नहीं है। यदि प्रासंगिक कॉलम NULL नहीं होने की गारंटी है, तो आप इन शर्तों को छोड़ सकते हैं।
इयान

3
हां, स्वीकृत उत्तर अब मान्य नहीं है, क्योंकि MYSQL 5.7 के बाद से यह वास्तव में स्वीकृत उत्तर होना चाहिए क्योंकि यह सार्वभौमिक है और इसके लिए अस्थायी तालिका की आवश्यकता नहीं है।
वह-बेन

1
बहुत कम अगर किसी दिए गए रिकॉर्ड की मैनी प्रतियां हैं (उदाहरण के लिए 100 को घटाकर 1), और उस स्थिति के साथ कई रिकॉर्ड। इसके बजाय stackoverflow.com/a/4685232/199364 की अनुशंसा करें । IMHO, ALWAYS लिंक किए गए दृष्टिकोण का उपयोग करते हैं; यह स्वाभाविक रूप से तेज़ तकनीक है।
टूलमेकरसेव

78

MySQL के पास उस तालिका को संदर्भित करने के बारे में प्रतिबंध है जिसे आप हटा रहे हैं। आप एक अस्थायी तालिका के साथ उसके आसपास काम कर सकते हैं, जैसे:

create temporary table tmpTable (id int);

insert  into tmpTable
        (id)
select  id
from    YourTable yt
where   exists
        (
        select  *
        from    YourTabe yt2
        where   yt2.title = yt.title
                and yt2.company = yt.company
                and yt2.site_id = yt.site_id
                and yt2.id > yt.id
        );

delete  
from    YourTable
where   ID in (select id from tmpTable);

टिप्पणियों में कोस्टानोस के सुझाव से:
ऊपर केवल धीमी क्वेरी DELETE है, ऐसे मामलों के लिए जहां आपके पास बहुत बड़ा डेटाबेस है। यह क्वेरी और तेज़ हो सकती है:

DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id

3
@ Chromar, यह ठीक काम करता है, सिवाय इसके कि जब खेतों में से किसी एक क्षेत्र में नल हों। उदाहरण: sqlfiddle.com/#/2/983f3/1
एक कोडर

1
सम्मिलित करें SQL एक महंगा है? मैं सोच रहा हूँ क्योंकि यह मेरे MySQL डेटाबेस में कई बार है।
कैसियो

4
जब आपके पास बड़ा डेटाबेस होता है, तो केवल धीमी क्वेरी ही यह DELETE होती है। यह क्वेरी और तेज़ हो सकती है:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
कोस्तानोस

@ कोस्टानोस न केवल DELETE, बल्कि INSERTअस्थायी तालिका में भी, मुझे एक लंबा समय लगा। तो tmp तालिका के लिए एक सूचकांक बहुत मदद कर सकता है create index tmpTable_id_index on tmpTable (id), कम से कम मेरे लिए।
जेजी.जी।

1
-: अपनी टेबल बड़े हैं, तो यह की कीमत जंगली के साथ एक सूचकांक जोड़नेcreate temporary table tmpTable (id int, PRIMARY KEY (id));
डलास क्लार्क

44

यदि IGNOREकथन मेरे मामले में काम नहीं करेगा, तो आप नीचे दिए गए कथन का उपयोग कर सकते हैं:

CREATE TABLE your_table_deduped LIKE your_table;


INSERT your_table_deduped
SELECT *
FROM your_table
GROUP BY index1_id,
         index2_id;

RENAME TABLE your_table TO your_table_with_dupes;

RENAME TABLE your_table_deduped TO your_table;

#OPTIONAL
ALTER TABLE `your_table` ADD UNIQUE `unique_index` (`index1_id`, `index2_id`);

#OPTIONAL
DROP TABLE your_table_with_dupes;

1
यदि आपके पास विदेशी कुंजी बाधा के साथ innoDB सेटिंग है तो बढ़िया काम करता है।
मगदामार्टिन

@Magdmartin, लेकिन विदेशी अड़चनें टेबल हटाने को नहीं रोकेंगी?
बसिलेव्स

1
IGNORE स्टेटमेंट ने मेरे लिए काम नहीं किया और इसने 5 मिलियन रिकॉर्ड्स को काट दिया। चीयर्स।
मौविस लेडफोर्ड

32

MySQL तालिकाओं पर डुप्लिकेट को हटाना एक सामान्य मुद्दा है, यह वास्तव में हाथ से पहले डुप्लिकेट से बचने के लिए एक लापता बाधा का परिणाम है। लेकिन यह आम मुद्दा आमतौर पर विशिष्ट आवश्यकताओं के साथ आता है ... इसके लिए विशिष्ट दृष्टिकोण की आवश्यकता होती है। दृष्टिकोण अलग-अलग होना चाहिए, उदाहरण के लिए, डेटा का आकार, डुप्लिकेट की गई प्रविष्टि, जिसे रखा जाना चाहिए (आम तौर पर पहला या अंतिम एक), चाहे अनुक्रमणिका रखी जाए, या क्या हम कोई अतिरिक्त प्रदर्शन करना चाहते हैं डुप्लिकेट किए गए डेटा पर कार्रवाई।

MySQL पर भी कुछ विशिष्टताएँ हैं, जैसे कि UPDATE पर प्रदर्शन करते समय FROM कारण पर एक ही तालिका को संदर्भित करने में सक्षम नहीं होने के कारण (यह MySQL त्रुटि को बढ़ाएगा # 1093)। एक अस्थायी तालिका के साथ आंतरिक क्वेरी का उपयोग करके इस सीमा को दूर किया जा सकता है (जैसा कि ऊपर कुछ दृष्टिकोणों पर सुझाव दिया गया है)। लेकिन बड़े डेटा स्रोतों के साथ काम करते समय यह आंतरिक क्वेरी विशेष रूप से अच्छा प्रदर्शन नहीं करेगी।

हालांकि, डुप्लिकेट को हटाने के लिए एक बेहतर दृष्टिकोण मौजूद है, जो कि कुशल और विश्वसनीय दोनों है, और जिसे आसानी से विभिन्न आवश्यकताओं के लिए अनुकूलित किया जा सकता है।

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

इसी से इसे हासिल किया जा सकता है। हमें देखते हुए एक मेज हैनिम्नलिखित कॉलम के साथ कर्मचारी है :

employee (id, first_name, last_name, start_date, ssn)

डुप्लिकेट के साथ पंक्तियों को हटाने के लिए ssn कॉलम के , और केवल पहली प्रविष्टि पाए जाने पर, निम्नलिखित प्रक्रिया का पालन किया जा सकता है:

-- create a new tmp_eployee table
CREATE TABLE tmp_employee LIKE employee;

-- add a unique constraint
ALTER TABLE tmp_employee ADD UNIQUE(ssn);

-- scan over the employee table to insert employee entries
INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id;

-- rename tables
RENAME TABLE employee TO backup_employee, tmp_employee TO employee;

तकनीकी व्याख्या

  • लाइन # 1 एक नया tmp_eployee बनाता है तालिका जिसमें कर्मचारी तालिका के समान संरचना है
  • लाइन # 2 नए में एक बाधा बाधा जोड़ता है आगे के डुप्लिकेट से बचने के tmp_eployee तालिका में
  • आईडी द्वारा मूल कर्मचारी तालिका पर लाइन # 3 स्कैन , नए में नई कर्मचारी प्रविष्टियाँ सम्मिलित करता है tmp_eployee तालिका करते हुए, डुप्लिकेट प्रविष्टियों की अनदेखी करते हुए
  • पंक्ति # 4 तालिकाओं का नाम बदल देती है, ताकि नए कर्मचारी तालिका में डुप्लिकेट के बिना सभी प्रविष्टियां हों, और पूर्व डेटा की एक बैकअप प्रति backup_employee पर रखी जाए तालिका

इस दृष्टिकोण का उपयोग करते हुए, 1.6M रजिस्टरों को 200k से कम में 6k में बदल दिया गया।

चेतन , इस प्रक्रिया का अनुसरण करते हुए, आप तेजी से और आसानी से अपने सभी डुप्लिकेट को हटा सकते हैं और रन करके एक UNIQUE बाधा बना सकते हैं:

CREATE TABLE tmp_jobs LIKE jobs;

ALTER TABLE tmp_jobs ADD UNIQUE(site_id, title, company);

INSERT IGNORE INTO tmp_jobs SELECT * FROM jobs ORDER BY id;

RENAME TABLE jobs TO backup_jobs, tmp_jobs TO jobs;

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

One पहले वाले के बजाय अंतिम प्रविष्टि रखने के लिए विविधता

कभी-कभी हमें पहले वाले के बजाय अंतिम डुप्लिकेट प्रविष्टि रखने की आवश्यकता होती है।

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT * FROM employee ORDER BY id DESC;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • # 3 लाइन पर, ORDER BY आईडी DESC क्लॉज बाकी के ऊपर प्राथमिकता प्राप्त करने के लिए अंतिम आईडी बनाता है

✔ डुप्लिकेट पर कुछ कार्य करने के लिए भिन्नता, उदाहरण के लिए डुप्लिकेट पर एक गिनती रखते हुए

कभी-कभी हमें डुप्लिकेट प्रविष्टियों पर कुछ और प्रसंस्करण करने की आवश्यकता होती है जो पाए जाते हैं (जैसे कि डुप्लिकेट की गिनती को ध्यान में रखते हुए)।

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • लाइन # 3 पर, एक नया कॉलम n_duplicates बनाया गया है
  • # 4 लाइन पर, INSERT INTO ... DUPLICATE KEY पर एक अतिरिक्त डुप्लिकेट मिलने पर अद्यतन अपडेट करने के लिए उपयोग किया जाता है (इस मामले में, एक काउंटर बढ़ाते हुए) INSERT INTO ... ON DUPLICATE कुंजी क्वेरी हो सकती है पाया डुप्लिकेट के लिए विभिन्न प्रकार के अद्यतन करने के लिए उपयोग किया जाता है।

ऑटो-वृद्धिशील क्षेत्र आईडी को पुनर्जीवित करने के लिए विविधता

कभी-कभी हम एक ऑटो-वृद्धिशील क्षेत्र का उपयोग करते हैं और, अनुक्रम को यथासंभव कॉम्पैक्ट रखने के लिए, हम नए अस्थायी तालिका में ऑटो-वृद्धिशील क्षेत्र को पुन: उत्पन्न करने के लिए डुप्लिकेट के विलोपन का लाभ उठा सकते हैं।

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

INSERT IGNORE INTO tmp_employee SELECT (first_name, last_name, start_date, ssn) FROM employee ORDER BY id;

RENAME TABLE employee TO backup_employee, tmp_employee TO employee;
  • लाइन # 3 पर, टेबल पर सभी फ़ील्ड्स का चयन करने के बजाय, आईडी फ़ील्ड को छोड़ दिया जाता है ताकि DB इंजन अपने आप एक नया इंजन उत्पन्न करे

✔ और बदलाव

वांछित व्यवहार के आधार पर कई और संशोधन भी उल्लेखनीय हैं। एक उदाहरण के रूप में, निम्नलिखित प्रश्न 1 के अलावा दूसरी अस्थायी तालिका का उपयोग करेंगे) पहले वाले के बजाय अंतिम प्रविष्टि रखें; और 2) पाए गए डुप्लिकेट पर एक काउंटर बढ़ाएं; 3) प्रविष्टि क्रम को पूर्व डेटा पर रखते समय ऑटो-वृद्धिशील फ़ील्ड आईडी पुनर्जीवित करें।

CREATE TABLE tmp_employee LIKE employee;

ALTER TABLE tmp_employee ADD UNIQUE(ssn);

ALTER TABLE tmp_employee ADD COLUMN n_duplicates INT DEFAULT 0;

INSERT INTO tmp_employee SELECT * FROM employee ORDER BY id DESC ON DUPLICATE KEY UPDATE n_duplicates=n_duplicates+1;

CREATE TABLE tmp_employee2 LIKE tmp_employee;

INSERT INTO tmp_employee2 SELECT (first_name, last_name, start_date, ssn) FROM tmp_employee ORDER BY id;

DROP TABLE tmp_employee;

RENAME TABLE employee TO backup_employee, tmp_employee2 TO employee;

27

एक और उपाय है:

DELETE t1 FROM my_table t1, my_table t2 WHERE t1.id < t2.id AND t1.my_field = t2.my_field AND t1.my_field_2 = t2.my_field_2 AND ...

4
यह @ rehriff के उत्तर से कैसे भिन्न है, जो उसने 6 महीने पहले प्रस्तुत किया था?
लॉरेंस डॉल

@ लॉरेंसडोल मुझे लगता है कि यह थोड़ा अधिक पठनीय है और यह भी कि मुझे लगता है कि जिस समय मैंने उत्तर दिया, उसका उत्तर वही नहीं था और मुझे लगता है कि उसका उत्तर संपादित हो गया।
मुस्तफा-टी

1
हम्म। मेरे लिए बहुत लंबा समय है जबकि रिकॉर्ड की संख्या बड़ी नहीं थी!
सूब १

8

यदि आपके पास बड़ी संख्या में रिकॉर्ड्स के साथ एक बड़ी तालिका है, तो उपरोक्त समाधान काम नहीं करेंगे या बहुत अधिक समय नहीं लेंगे। फिर हमारे पास एक अलग समाधान है

-- Create temporary table

CREATE TABLE temp_table LIKE table1;

-- Add constraint
ALTER TABLE temp_table ADD UNIQUE(title, company,site_id);

-- Copy data
INSERT IGNORE INTO temp_table SELECT * FROM table1;

-- Rename and drop
RENAME TABLE table1 TO old_table1, temp_table TO table1;
DROP TABLE old_table1;

6

मेरे पास SQLServer के लिए यह क्वेरी स्निपेट है लेकिन मुझे लगता है कि इसे थोड़े बदलाव के साथ दूसरों के DBMS में इस्तेमाल किया जा सकता है:

DELETE
FROM Table
WHERE Table.idTable IN  (  
    SELECT MAX(idTable)
    FROM idTable
    GROUP BY field1, field2, field3
    HAVING COUNT(*) > 1)

मैं आपको यह बताना भूल गया कि यह क्वेरी डुप्लिकेट की गई पंक्तियों की सबसे कम आईडी के साथ पंक्ति को नहीं हटाती है। यदि आपके लिए यह कार्य इस क्वेरी को आज़माता है:

DELETE
FROM jobs
WHERE jobs.id IN  (  
    SELECT MAX(id)
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING COUNT(*) > 1)

यदि किसी समूह के दो से अधिक डुप्लिकेट हैं तो यह काम नहीं करेगा।
OMG पॉनीज

11
दुर्भाग्य से, MySQL आपको उस तालिका से चयन करने की अनुमति नहीं देता है जिसे आप से हटा रहे हैंERROR 1093: You can't specify target table 'Table' for update in FROM clause
एंडोमर

1
"You can't specify target table 'Table' for update in FROM..."त्रुटि को हल करने के लिए , उपयोग करें: DELETE FROM Table WHERE Table.idTable IN ( SELECT MAX(idTable) FROM (SELECT * FROM idTable) AS tmp GROUP BY field1, field2, field3 HAVING COUNT(*) > 1)जो MySQL को एक अस्थायी तालिका बनाने के लिए मजबूर करता है। हालांकि बड़े डेटासेट में यह बहुत धीमा है ... ऐसे मामलों में, मैं एंडोमार के कोड की सिफारिश करूंगा, जो बहुत तेज है।
लेप

6

तेज़ तरीका अलग-अलग पंक्तियों को एक अस्थायी तालिका में सम्मिलित करना है। डिलीट का उपयोग करते हुए, मुझे 8 मिलियन पंक्तियों की तालिका से डुप्लिकेट को हटाने में कुछ घंटे लगे। इंसर्ट और विशिष्ट का उपयोग करते हुए, इसमें सिर्फ 13 मिनट का समय लगा।

CREATE TABLE tempTableName LIKE tableName;  
CREATE INDEX ix_all_id ON tableName(cellId,attributeId,entityRowId,value);  
INSERT INTO tempTableName(cellId,attributeId,entityRowId,value) SELECT DISTINCT cellId,attributeId,entityRowId,value FROM tableName;  
TRUNCATE TABLE tableName;
INSERT INTO tableName SELECT * FROM tempTableName; 
DROP TABLE tempTableName;  

1
आपकी 4 TRUNCATE TABLE tableNameवीं पंक्ति INSERT INTO tableName SELECT * FROM tempTableName;
सना

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;

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


1
यह वास्तव में mysql में कहीं भी अच्छी तरह से काम करता है 5.7 जगह स्वीकृत समाधान काम नहीं करता है
रॉबिन

5

DELETE JOIN स्टेटमेंट का उपयोग करके डुप्लिकेट पंक्तियों को हटाएं MySQL आपको DELETE JOIN स्टेटमेंट प्रदान करता है जिसका उपयोग करके आप डुप्लिकेट पंक्तियों को जल्दी से हटा सकते हैं।

निम्नलिखित कथन डुप्लिकेट पंक्तियों को हटाता है और उच्चतम आईडी रखता है:

DELETE t1 FROM contacts t1
    INNER JOIN
contacts t2 WHERE
t1.id < t2.id AND t1.email = t2.email;

5

मुझे एक आसान रास्ता मिल गया। (नवीनतम रखें)

DELETE t1 FROM tablename t1 INNER JOIN tablename t2 
WHERE t1.id < t2.id AND t1.column1 = t2.column1 AND t1.column2 = t2.column2;

4

सभी मामलों के लिए सरल और तेज:

CREATE TEMPORARY TABLE IF NOT EXISTS _temp_duplicates AS (SELECT dub.id FROM table_with_duplications dub GROUP BY dub.field_must_be_uniq_1, dub.field_must_be_uniq_2 HAVING COUNT(*)  > 1);

DELETE FROM table_with_duplications WHERE id IN (SELECT id FROM _temp_duplicates);

त्रुटि कोड: 1055. चयनित सूची का अभिव्यक्ति # 2 ग्रुप बीओजी खंड में नहीं है और इसमें गैर-पृथक कॉलम 'डबिड' शामिल है, जो ग्रुप बीओ क्लॉज में स्तंभों पर कार्यात्मक रूप से निर्भर नहीं है; यह sql_mode = only_full_group_by के साथ असंगत है
Swoogan

आप sql_mode के साथ "हार्ड कंट्रोल" को निष्क्रिय कर सकते हैं, stackoverflow.com/questions/23921117/disable-only-full-group-by
artemiuz

4

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

DELETE t1 FROM tablename t1
INNER JOIN tablename t2 
WHERE 
    t1.id < t2.id AND
    t1.title = t2.title AND
    t1.company=t2.company AND
    t1.site_ID=t2.site_ID;

यह धीमा है (5w + पंक्तियाँ, लॉक
वेट

3

मैं कभी भी इस पृष्ठ पर आता रहता हूँ जब तक मैं Google "डुप्लिकेट फ़ॉर्म mysql हटाता हूँ", लेकिन मेरे डिज़ाइन समाधान के लिए काम नहीं करते क्योंकि मेरे पास एक InnoDB mysql टेबल है

यह कोड कभी भी बेहतर काम करता है

CREATE TABLE tableToclean_temp LIKE tableToclean;
ALTER TABLE tableToclean_temp ADD UNIQUE INDEX (fontsinuse_id);
INSERT IGNORE INTO tableToclean_temp SELECT * FROM tableToclean;
DROP TABLE tableToclean;
RENAME TABLE tableToclean_temp TO tableToclean;

tableToclean = तालिका का नाम जिसे आपको साफ़ करने की आवश्यकता है

tableToclean_temp = बनाई गई और हटा दी गई एक अस्थायी तालिका


2

यह समाधान डुप्लिकेट को एक तालिका में और अन्य को एक में ले जाएगा

-- speed up creating uniques table if dealing with many rows
CREATE INDEX temp_idx ON jobs(site_id, company, title, location);

-- create the table with unique rows
INSERT jobs_uniques SELECT * FROM
    (
    SELECT * 
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) > 1
    UNION
    SELECT *
    FROM jobs
    GROUP BY site_id, company, title, location
    HAVING count(1) = 1
) x

-- create the table with duplicate rows
INSERT jobs_dupes 
SELECT * 
FROM jobs
WHERE id NOT IN
(SELECT id FROM jobs_uniques)

-- confirm the difference between uniques and dupes tables
SELECT COUNT(1)
AS jobs, 
(SELECT COUNT(1) FROM jobs_dupes) + (SELECT COUNT(1) FROM jobs_uniques)
AS sum
FROM jobs

आपने संघ को क्यों लिया और सिर्फ नहीं SELECT * FROM jobs GROUP BY site_id, company, title, location?
तिमिरत्रन

2

संस्करण 8.0 (2018) के अनुसार, MySQL आखिरकार विंडो फ़ंक्शन का समर्थन करता है

विंडो फ़ंक्शंस आसान और कुशल दोनों हैं। यहां एक समाधान है जो दर्शाता है कि इस असाइनमेंट को हल करने के लिए उनका उपयोग कैसे करें।

एक उपश्रेणी में, हम समूहों के ROW_NUMBER()भीतर तालिका में प्रत्येक रिकॉर्ड के लिए एक स्थिति निर्दिष्ट करने के लिए उपयोग कर सकते हैं column1/column2, द्वारा आदेश दिया गया है id। यदि कोई डुप्लिकेट नहीं है, तो रिकॉर्ड को पंक्ति संख्या मिल जाएगी 1। यदि डुप्लिकेट मौजूद है, तो वे आरोही id(शुरू में 1) द्वारा क्रमांकित किए जाएंगे ।

एक बार रिकॉर्ड को ठीक से सबक्वेरी में क्रमांकित किया जाता है, बाहरी क्वेरी सिर्फ उन सभी रिकॉर्डों को हटा देती है जिनकी पंक्ति संख्या 1 नहीं है।

प्रश्न:

DELETE FROM tablename
WHERE id IN (
    SELECT id
    FROM (
        SELECT 
            id, 
            ROW_NUMBER() OVER(PARTITION BY column1, column2 ORDER BY id) rn
        FROM output
    ) t
    WHERE rn > 1
)

1

तालिका में डुप्लिकेट रिकॉर्ड को हटाने के लिए।

delete from job s 
where rowid < any 
(select rowid from job k 
where s.site_id = k.site_id and 
s.title = k.title and 
s.company = k.company);

या

delete from job s 
where rowid not in 
(select max(rowid) from job k 
where s.site_id = k.site_id and
s.title = k.title and 
s.company = k.company);

1
-- Here is what I used, and it works:
create table temp_table like my_table;
-- t_id is my unique column
insert into temp_table (id) select id from my_table GROUP by t_id;
delete from my_table where id not in (select id from temp_table);
drop table temp_table;

0

अद्वितीय स्तंभों के साथ रिकॉर्ड डुप्लिकेट करने के लिए, जैसे COL1, COL2, COL3 को दोहराया नहीं जाना चाहिए (मान लीजिए कि हमने तालिका संरचना में 3 कॉलम अनुपलब्ध हैं और कई डुप्लिकेट प्रविष्टियाँ तालिका में बनाई गई हैं)

DROP TABLE TABLE_NAME_copy;
CREATE TABLE TABLE_NAME_copy LIKE TABLE_NAME;
INSERT INTO TABLE_NAME_copy
SELECT * FROM TABLE_NAME
GROUP BY COLUMN1, COLUMN2, COLUMN3; 
DROP TABLE TABLE_NAME;
ALTER TABLE TABLE_NAME_copy RENAME TO TABLE_NAME;

आशा है कि देव की मदद करेंगे।


0

टी एल; टी.आर.;

इस समस्या को हल करने के लिए एक बहुत वर्णित ट्यूटोरियल mysqltutorial.org पर पाया जा सकता है साइट :

कैसे MySQL में डुप्लिकेट पंक्तियों को हटाने के लिए

यह स्पष्ट रूप से दिखाया गया है कि तीन अलग-अलग तरीकों से डुप्लिकेट पंक्तियों को कैसे हटाया जाए :

क)DELETE JOIN कथन का उपयोग करना

बी) एक मध्यवर्ती तालिका का उपयोग करना

सी)ROW_NUMBER() फ़ंक्शन का उपयोग करना

मुझे उम्मीद है कि यह किसी की मदद करेगा।


0

मेरे पास एक तालिका है जो आईडी पंक्ति में एक प्राथमिक कुंजी जोड़ना भूल जाती है। हालांकि आईडी पर auto_increment है। लेकिन एक दिन, एक सामान डेटाबेस पर mysql बिन लॉग को दोहराता है जो कुछ डुप्लिकेट पंक्तियाँ सम्मिलित करता है।

मैं डुप्लिकेट पंक्ति को हटा देता हूं

  1. अद्वितीय डुप्लिकेट पंक्तियों का चयन करें और उन्हें निर्यात करें

select T1.* from table_name T1 inner join (select count(*) as c,id from table_name group by id) T2 on T1.id = T2.id where T2.c > 1 group by T1.id;

  1. आईडी द्वारा डुप्लिकेट पंक्तियों को हटाएं

  2. निर्यात किए गए डेटा से पंक्ति डालें।

  3. फिर id पर प्राथमिक कुंजी जोड़ें


-2

मैं थोड़ा और अधिक विशिष्ट होना पसंद करता हूं क्योंकि मैं यहां से जो रिकॉर्ड हटाता हूं वह मेरा समाधान है:

delete
from jobs c1
where not c1.location = 'Paris'
and  c1.site_id > 64218
and exists 
(  
select * from jobs c2 
where c2.site_id = c1.site_id
and   c2.company = c1.company
and   c2.location = c1.location
and   c2.title = c1.title
and   c2.site_id > 63412
and   c2.site_id < 64219
)

-4

आप इस कोड से डुप्लिकेट रिकॉर्ड आसानी से हटा सकते हैं।

$qry = mysql_query("SELECT * from cities");
while($qry_row = mysql_fetch_array($qry))
{
$qry2 = mysql_query("SELECT * from cities2 where city = '".$qry_row['city']."'");

if(mysql_num_rows($qry2) > 1){
    while($row = mysql_fetch_array($qry2)){
        $city_arry[] = $row;

        }

    $total = sizeof($city_arry) - 1;
        for($i=1; $i<=$total; $i++){


            mysql_query( "delete from cities2 where town_id = '".$city_arry[$i][0]."'");

            }
    }
    //exit;
}

3
यह बहुत खराब रूप है- डेटाबेस कार्यों को DB में किया जाना चाहिए, जहां वे बहुत तेजी से होते हैं, बजाय php / mysql के बीच लगातार डेटा भेजने के कारण क्योंकि आप एक दूसरे से बेहतर जानते हैं।
अधिकतम

-4

मुझे यह पाठ क्षेत्रों के साथ करना था और सूचकांक पर 100 बाइट्स की सीमा के पार आया था।

मैंने इसे एक कॉलम जोड़कर हल किया, खेतों की एक md5 हैश और परिवर्तन कर रहा था।

ALTER TABLE table ADD `merged` VARCHAR( 40 ) NOT NULL ;
UPDATE TABLE SET merged` = MD5(CONCAT(`col1`, `col2`, `col3`))
ALTER IGNORE TABLE table ADD UNIQUE INDEX idx_name (`merged`);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.