মাইএসকিউএলে সদৃশ সারিগুলি সরান


375

নিম্নলিখিত ক্ষেত্রগুলি সহ আমার একটি টেবিল রয়েছে:

id (Unique)
url (Unique)
title
company
site_id

এখন, আমার একই সারিগুলি সরিয়ে ফেলতে হবে title, company and site_id। এটি করার একটি উপায় হ'ল একটি স্ক্রিপ্ট ( PHP) সহ নিম্নোক্ত এসকিউএল ব্যবহার করা হবে :

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

এই কোয়েরিটি চালানোর পরে, আমি একটি সার্ভার সাইড স্ক্রিপ্ট ব্যবহার করে সদৃশগুলি সরাতে পারি।

তবে, আমি জানতে চাই যে এটি কেবল এসকিউএল কোয়েরি ব্যবহার করে করা যায় কিনা।


1
দ্রুত প্রশ্ন: সর্বদা সদৃশ (শিরোনাম, সংস্থা, সাইট_আইডি) উপস্থিত না থাকতে চান? যদি তাই হয়, আমি শিরোনাম, সংস্থা, এবং সাইট_আইডি অনন্য হতে প্রয়োগ করতে ডাটাবেসে একটি সীমাবদ্ধতা সেট করব। যার অর্থ হ'ল আপনার একটি পরিষ্কার প্রক্রিয়া প্রয়োজন হবে না। এবং এটি কেবলমাত্র এসকিউএল এর একক লাইন লাগে।
জে। Polfer

1
দয়া করে এই স্ট্যাকওভারফ্লোটির লিঙ্কটি দেখুন .এটি আমার জন্য কবজ হিসাবে কাজ করেছিল।

আমি এই সমাধানটি (অন্য থ্রেডে পোস্ট করা) সুপারিশ করতে পারি: stackoverflow.com/a/4685232/195835
সাইমন ইস্ট

উত্তর:


607

এটি করার একটি খুব সহজ উপায় হ'ল UNIQUE3 কলামে একটি সূচি যুক্ত করা। আপনি যখন ALTERবিবৃতিটি লিখবেন তখন IGNOREকীওয়ার্ডটি অন্তর্ভুক্ত করুন । তাই ভালো:

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

এটি সমস্ত সদৃশ সারি বাদ দেবে। একটি অতিরিক্ত সুবিধা হিসাবে, ভবিষ্যতে INSERTsসদৃশগুলি ত্রুটিযুক্ত হয়ে যাবে। সর্বদা হিসাবে, আপনি এই জাতীয় কিছু চালানোর আগে একটি ব্যাকআপ নিতে চাইতে পারেন ...


8
আকর্ষণীয় , কিন্তু সেই অনুলিপিগুলি অপসারণের জন্য আইজিএনওর ধারাটি অনুমানগুলি একটি উদ্বেগ যা প্রয়োজনের সাথে মেলে না। ভুল মানগুলি নিকটতম গ্রহণযোগ্য ম্যাচের শব্দকে ছাঁটাই করা আপনার পক্ষে ভাল?
ওএমজি পনিস

75
কেবল রেকর্ডের জন্য যদি আপনি ইনোডিবি ব্যবহার করেন তবে আপনার এটির সাথে সমস্যা হতে পারে, ইনোডিবি ডাটাবেসগুলির সাথে অল্টার ইগনোর টেবিল ব্যবহার সম্পর্কে একটি জানা বাগ রয়েছে।
ডার্কম্যান্টিস

27
উপরে বর্ণিত বাগ @ ডার্কম্যান্টিস উল্লেখ করেছে এবং এর সমাধান রয়েছে
জর্দান আর্সেনো

42
InnoDB টেবিলগুলির জন্য প্রথমে নিম্নলিখিত কোয়েরিটি set session old_alter_table=1;
সম্পাদন করুন


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

মাইএসকিউএল এ, আপনি এটি আরও বেশি সরল করতে পারবেন এনএলএল-সেফ সমতুল অপারেটর (ওরফে "স্পেসশিপ অপারেটর" ) এর মাধ্যমে:

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
@ নাসিম: আপনার অবশ্যই এই উত্তর থেকে কিছু আলাদা করা উচিত কারণ এটি আমার জন্য নিখুঁতভাবে কাজ করে (মাইএসকিউএল)।
লরেন্স ডল

3
আমার মতো যে কেউ বিভ্রান্ত হয়েছিল তার জন্য, NULL তুলনার শর্তাদি প্রয়োজন কারণ মুল এসএসকিউএল এ এনইউএল এর সাথে সমান হয় না। যদি সম্পর্কিত কলামগুলি নুল না হওয়ার গ্যারান্টিযুক্ত থাকে তবে আপনি এই শর্তগুলি বাদ দিতে পারেন।
ইয়ান

3
হ্যাঁ, গৃহীত উত্তরটি আর বৈধ নয়, যেহেতু এমওয়াইএসকিউএল ৫.7 তাই এটি সর্বজনীন হওয়ায় এটি সত্যই গ্রহণযোগ্য উত্তর হওয়া উচিত এবং অস্থায়ী টেবিল তৈরির প্রয়োজনও নেই।
সেই-বেন

1
যদি একটি প্রদত্ত রেকর্ডের অনেকগুলি অনুলিপি থাকে (উদাহরণস্বরূপ 100 টি 1 এ হ্রাস করা হবে) এবং সেই শর্তটি সহ অনেক রেকর্ড রয়েছে। পরিবর্তে stackoverflow.com/a/4685232/199364 সুপারিশ করুন। আইএমএইচও, সর্বদা সংযুক্ত পদ্ধতির ব্যবহার করে; এটি একটি সহজাত দ্রুত কৌশল।
নির্মাতা স্টিভ

78

মাইএসকিউএলের যে সারণিটি আপনি মুছে ফেলছেন তা উল্লেখ করার বিষয়ে বিধিনিষেধ রয়েছে। অস্থায়ী টেবিলের সাহায্যে আপনি এটিকে ঘিরে কাজ করতে পারেন, যেমন:

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

মন্তব্যে কোস্টানোসের পরামর্শ থেকে:
উপরের একমাত্র ধীর অনুসন্ধানটি হ্রাস করা হয়, যেখানে আপনার খুব বড় ডেটাবেস রয়েছে for এই কোয়েরিটি দ্রুত হতে পারে:

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

3
@ এবং এন্ডোমার, যেখানে ক্লাসের কোনও একটি ক্ষেত্রে নাল রয়েছে সেগুলি বাদ দিলে এটি ঠিক কাজ করে। উদাহরণ: sqlfiddle.com/#!2/983f3/1
একটি কোডার

1
Sোকানো এসকিউএল কি ব্যয়বহুল? আমি ভাবছি কারণ এটি আমার মাইএসকিউএল ডেটাবেজে বার হয়ে যায়।
ক্যাসিও

4
আপনার কাছে বড় ডেটাবেস থাকলে সেক্ষেত্রে একমাত্র ধীর অনুসন্ধানটি এটি মুছে ফেলবে। এই ক্যোয়ারীটি দ্রুততর হতে পারে:DELETE FROM YourTable USING YourTable, tmpTable WHERE YourTable.id=tmpTable.id
কোস্টানোস

@ কোস্টানোস কেবল নয় DELETE, INSERTঅস্থায়ী টেবিলের কাছেও আমার অনেক সময় লেগেছে। create index tmpTable_id_index on tmpTable (id)কমপক্ষে আমার জন্য tmp টেবিলের জন্য একটি সূচক অনেক সাহায্য করতে পারে ।
Jiezhi.G

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
বিদেশী কী সীমাবদ্ধতার সাথে যদি নির্দোষ ডিবি সেট থাকে তবে দুর্দান্ত কাজ করে।
ম্যাগডমার্টিন

@ ম্যাগডমার্টিন, কিন্তু বিদেশী বাধা কি টেবিল মোছার প্রতিরোধ করবে না?
বেসিলিভ

1
আইগনোরের বিবৃতিটি আমার পক্ষে কার্যকর হয়নি এবং এটি ৫ মিলিয়ন রেকর্ড ছাড়ার ক্ষেত্রে দুর্দান্ত কাজ করেছে। চিয়ার্স।
মাওভিস লেডফোর্ড

32

মাইএসকিউএল টেবিলগুলিতে সদৃশ মুছে ফেলা একটি সাধারণ সমস্যা, যা হাতের আগে সেই সদৃশগুলি এড়ানোর জন্য জেনারিকভাবে অনুপস্থিত প্রতিবন্ধকতার ফলাফল। তবে এই সাধারণ সমস্যাটি সাধারণত নির্দিষ্ট প্রয়োজনগুলির সাথে আসে ... যার জন্য নির্দিষ্ট পদ্ধতির প্রয়োজন হয়। পদ্ধতির উপর নির্ভর করে ভিন্ন হওয়া উচিত, উদাহরণস্বরূপ, ডেটার আকার, ডুপ্লিকেট এন্ট্রি যা রাখা উচিত (সাধারণত প্রথম বা শেষ একটি), সেখানে সূচি রাখতে হবে কিনা, বা আমরা কোনও অতিরিক্ত সম্পাদন করতে চাই কিনা সদৃশ তথ্য উপর ক্রিয়া।

মাইএসকিউএল-তে নিজেও কিছু বৈশিষ্ট্য রয়েছে যেমন কোনও টেবিল আপডেটের সময় এটি কোনও ফর্মের কারণে একই টেবিলটি উল্লেখ করতে সক্ষম না হওয়া (এটি মাইএসকিউএল ত্রুটি # 1093 বাড়িয়ে তুলবে)। এই সীমাবদ্ধতা অস্থায়ী টেবিল (উপরের কিছু পদ্ধতির পরামর্শ হিসাবে) দিয়ে অভ্যন্তরীণ কোয়েরি ব্যবহার করে কাটিয়ে উঠতে পারে। তবে বড় ডেটা উত্সগুলির সাথে কাজ করার সময় এই অভ্যন্তরীণ কোয়েরিটি বিশেষভাবে ভাল সম্পাদন করবে না।

তবে সদৃশ অপসারণের জন্য আরও ভাল পদ্ধতির উপস্থিতি রয়েছে, এটি দক্ষ এবং নির্ভরযোগ্য উভয়ই এবং এটি সহজেই বিভিন্ন প্রয়োজনের সাথে মানিয়ে নেওয়া যায়।

সাধারণ ধারণাটি হ'ল একটি নতুন অস্থায়ী টেবিল তৈরি করা, সাধারণত আরও অনুলিপিগুলি এড়ানোর জন্য একটি অনন্য বাধা যুক্ত করা এবং নকলগুলির যত্ন নেওয়ার সময় আপনার পূর্বের টেবিল থেকে ডেটা নতুনটিতে সন্নিবেশ করানো। এই পদ্ধতির সহজ মাইএসকিউএল INSERT প্রশ্নের উপর নির্ভর করে, আরও নকলগুলি এড়ানোর জন্য একটি নতুন প্রতিবন্ধকতা তৈরি করে এবং সদৃশ সন্ধান করার জন্য একটি অভ্যন্তরীণ কোয়েরি ব্যবহারের প্রয়োজন এবং স্মৃতিতে রাখা উচিত এমন একটি অস্থায়ী টেবিল (এগুলি বড় ডেটা উত্সগুলিও ফিট করে) ips

এভাবেই এটি অর্জন করা যায়। নিম্নলিখিত কলামগুলি সহ আমাদের একটি টেবিল কর্মচারী রয়েছে:

employee (id, first_name, last_name, start_date, 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 আসল কর্মচারী টেবিলের উপরে স্ক্যান করে , ডুপ্লিকেটড এন্ট্রিগুলি উপেক্ষা করার সময়, নতুন টিএমপি_প্লোয়ে টেবিলটিতে নতুন কর্মচারী প্রবেশ সন্নিবেশ করানো হবে
  • লাইন # 4 টেবিলগুলির নাম পরিবর্তন করে, যাতে নতুন কর্মচারী টেবিলটি নকল ছাড়াই সমস্ত এন্ট্রি ধারণ করে এবং পূর্ববর্তী ডেটার একটি ব্যাকআপ অনুলিপি ব্যাকআপ_এম্পলয়ে টেবিলে রাখা হয়

এই পদ্ধতির ব্যবহার করে, 1.6m রেজিস্টার 200s কম সময়ে 6k রূপান্তরিত করা হয়েছে।

চেতান , এই প্রক্রিয়াটি অনুসরণ করে, আপনি দ্রুত এবং সহজেই আপনার সমস্ত নকল মুছে ফেলতে এবং চালিয়ে একটি অনন্য বাধা তৈরি করতে পারেন:

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;

অবশ্যই, নকল মুছে ফেলার সময় এই প্রক্রিয়াটিকে আরও বিভিন্ন প্রয়োজনের সাথে খাপ খাইবার জন্য আরও সংশোধন করা যেতে পারে। কিছু উদাহরণ অনুসরণ।

Entry প্রথম প্রবেশের পরিবর্তে শেষ এন্ট্রি রাখার জন্য পার্থক্য

কখনও কখনও আমাদের প্রথমটির পরিবর্তে শেষ সদৃশ এন্ট্রি রাখা প্রয়োজন।

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 লাইনে, অর্ডার বাই আইডি ডিইএসসি ক্লজটি সর্বশেষ আইডির বাকী অংশগুলির চেয়ে অগ্রাধিকার পেতে দেয়

D সদৃশগুলিতে কিছু কাজ সম্পাদনের জন্য বৈকল্পিকতা, উদাহরণস্বরূপ পাওয়া নকলগুলিতে একটি গণনা রাখা

কখনও কখনও আমাদের পাওয়া নকল প্রবেশগুলি (যেমন ডুপ্লিকেটগুলির একটি গণনা রাখা) সম্পর্কে আরও কিছু প্রক্রিয়াজাতকরণ করা দরকার।

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_ নকল তৈরি করা হয়েছে
  • লাইন # 4-তে, সন্নিবেশটি অন্তর্ভুক্ত করুন ... অনুলিপি কী আপডেটের সাথে অনুসন্ধানের কোনও ডুপ্লিকেট পাওয়া গেলে একটি অতিরিক্ত আপডেট করতে ব্যবহৃত হয় (এই ক্ষেত্রে, একটি কাউন্টার বাড়ানো হচ্ছে) INSERT INTO ... DUPLICATE KEY আপডেটের ক্যোয়ারী হতে পারে পাওয়া নকলের জন্য বিভিন্ন ধরণের আপডেট করতে ব্যবহৃত হয়।

The অটো-ইনক্রিমেন্টাল ফিল্ড আইডি পুনরায় জন্মানোর জন্য পার্থক্য

কখনও কখনও আমরা একটি অটো-ইনক্রিমেন্টাল ক্ষেত্র ব্যবহার করি এবং সূচকটিকে যথাসম্ভব কমপ্যাক্ট রাখার জন্য, আমরা অস্থায়ী সারণীতে স্বয়ংক্রিয়-বর্ধিত ক্ষেত্রটি পুনঃজুনাতে ডুপ্লিকেটগুলি মুছে ফেলার সুবিধা নিতে পারি।

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 তে, টেবিলের সমস্ত ক্ষেত্র নির্বাচন করার পরিবর্তে, আইডি ফিল্ডটি এড়িয়ে যায় যাতে ডিবি ইঞ্জিন স্বয়ংক্রিয়ভাবে একটি নতুন তৈরি করে

✔ আরও বিভিন্নতা

পছন্দসই আচরণের উপর নির্ভর করে আরও অনেকগুলি পরিবর্তনও করণীয়। উদাহরণস্বরূপ, নীচের প্রশ্নাগুলি দ্বিতীয় অস্থায়ী টেবিলটি ব্যবহার করবে, 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
@ রিহারিফের উত্তর থেকে এটি কীভাবে আলাদা, যা তিনি 6 মাস আগে জমা দিয়েছিলেন?
লরেন্স ডল

@ লরেন্সডল আমি অনুমান করি যে এটি কিছুটা বেশি পাঠযোগ্য এবং আমিও মনে করি যে আমি উত্তর দেওয়ার সময় তার উত্তর এক রকম ছিল না এবং আমি মনে করি যে তার উত্তর সম্পাদিত হয়েছে got
মোস্তফা -T

1
হুম। রেকর্ডের সংখ্যাটি বড় না হলেও আমার পক্ষে এটি অনেক দীর্ঘ সময় নেয়!
SuB

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

এসকিউএল সার্ভারের কাছে আমার কাছে এই ক্যোয়ারী স্নিপেট রয়েছে তবে আমি মনে করি এটি অন্য পরিবর্তন করতে ডিবিএমএসে ব্যবহার করা যেতে পারে:

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)

কোনও গ্রুপের দু'টির বেশি অনুলিপি থাকলে এটি কাজ করবে না।
ওএমজি পনিজ

11
দুর্ভাগ্যক্রমে, মাইএসকিউএল আপনি যে সারণী থেকে মুছে 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)যা মাইএসকিউএলকে অস্থায়ীভাবে সারণী তৈরি করতে বাধ্য করে। তবে এটি বড় ডেটাসেটগুলিতে খুব ধীরে ধীরে ... এই জাতীয় ক্ষেত্রে, আমি আন্দোমার কোডটি সুপারিশ করব, যা আরও দ্রুত।
লিপ

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
আপনার চতুর্থ লাইনটি বলা উচিত TRUNCATE TABLE tableNameএবং 5 তম লাইনে বলা উচিত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;

৪) সারিগুলি মুছে ফেলুন যেগুলি টোপ হিসাবে চিহ্নিত করা হয়নি

delete from mytable where tokeep is null;

5) যুক্ত কলামটি বাদ দিন

alter table mytable drop tokeep;

আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি যুক্ত হওয়া সীমাবদ্ধতাটি রাখুন, যাতে ভবিষ্যতে নতুন সদৃশগুলি প্রতিরোধ করা হয়।


1
এটি mysql 5.7 এ সত্যই ভাল কাজ করেছে কোথাও গৃহীত সমাধানগুলি আর কাজ করে না
রবিন 31

5

ডিলিকেট সারিগুলি মুছুন জয়েন স্টেটমেন্ট ব্যবহার করে মাইএসকিউএল আপনাকে মুছে ফেলুন যুক্ত বিবরণ সরবরাহ করে যা আপনি নকল সারিগুলি দ্রুত সরাতে ব্যবহার করতে পারেন।

নিম্নলিখিত বিবৃতিটি সদৃশ সারিগুলি মুছে ফেলে এবং সর্বোচ্চ আইডি রাখে:

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 = কেবল_ সম্পূর্ণ_গোষ্ঠী_বিশেষের সাথে বেমানান
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;

এটি ধীর (5 ডাব্লু + সারি, লক
ওয়েট আউটআউট

3

আমি এই পৃষ্ঠায় যে কোনও সময় পরিদর্শন করতে থাকি যখনই আমি "ডুপ্লিকেটগুলি ফর্ম মাইএসকিএল" গুগল করি তবে আমার পূর্ববর্তী সমাধানগুলির জন্য কাজ হয় না কারণ আমার কাছে একটি ইনোডিবি মাইএসকিএল টেবিল রয়েছে

এই কোড যে কোনও সময় ভাল কাজ করে

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) হিসাবে, মাইএসকিউএল শেষ পর্যন্ত উইন্ডো ফাংশন সমর্থন করে

উইন্ডো ফাংশন উভয় সহজ এবং দক্ষ। এখানে একটি সমাধান রয়েছে যা দেখায় যে এই অ্যাসাইনমেন্টটি সমাধান করতে কীভাবে তাদের ব্যবহার করবেন।

একটি সাবকিউরিতে, আমরা আদেশ অনুসারে দলগুলির ROW_NUMBER()মধ্যে সারণীতে প্রতিটি রেকর্ডকে একটি অবস্থান নির্ধারণ করতে ব্যবহার করতে পারি । যদি কোনও সদৃশ না থাকে, রেকর্ডটি সারি নম্বর পাবে । যদি সদৃশটি বিদ্যমান থাকে তবে সেগুলি আরোহণের দ্বারা গণনা করা হবে (শুরু করে)column1/column2id1id1 )।

সাবকিউরিতে রেকর্ডগুলি যথাযথভাবে গণনা করা হলে, বাইরের ক্যোয়ারী কেবল সমস্ত রেকর্ড মুছে দেয় যার সারি সংখ্যা 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 এ পাওয়া যাবে সাইটে :

মাইএসকিউএলে সদৃশ সারিগুলি কীভাবে মুছবেন

এটি তিনটি বিভিন্ন উপায়ে সদৃশ সারিগুলি কীভাবে মুছবেন তা খুব স্পষ্টভাবে দেখানো হয়েছে :

ক)DELETE JOIN বিবৃতি ব্যবহার করে

খ) একটি মধ্যবর্তী টেবিল ব্যবহার করে

গ)ROW_NUMBER() ফাংশন ব্যবহার করে

আমি আশা করি এটি কারও সাহায্য করবে।


0

আমার একটি টেবিল রয়েছে যা আইডি সারিতে প্রাথমিক কী যুক্ত করতে ভুলে যায়। যদিও আইডিতে স্বতঃআগ্রহ রয়েছে। কিন্তু একদিন, একটি স্টাফ ডাটাবেসে মাইএসকিএল বিন লগ পুনরায় খেলায় যা কিছু নকল সারি প্রবেশ করায়।

আমি সদৃশ সারিটি সরিয়ে দিয়েছি

  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. রফতানি করা ডেটা থেকে সারিটি sertোকান।

  3. তারপরে আইডিতে প্রাথমিক কী যুক্ত করুন


-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
এটি খুব খারাপ ফর্ম database ডাটাবেসের কাজগুলি ডিবিতে করা উচিত, যেখানে পিএইচপি / মাইএসকিএল-এর মধ্যে অবিচ্ছিন্নভাবে ডেটা প্রেরণ করার পরিবর্তে তারা অনেক বেশি দ্রুত হয় কারণ আপনি অন্যটির চেয়ে ভাল জানেন।
সর্বোচ্চ

-4

আমাকে পাঠ্য ক্ষেত্রগুলির সাথে এটি করতে হয়েছিল এবং সূচীতে 100 বাইটের সীমাটি পেরিয়ে এসেছি।

আমি একটি কলাম যুক্ত করে, ক্ষেত্রগুলির একটি এমডি 5 হ্যাশ করে এবং এটির পরিবর্তন করে সমাধান করেছি।

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`);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.