PostgreSQL এ সদৃশ রেকর্ডস মুছুন


113

আমার পোস্টগ্রিজ এসকিউএল 8.3.8 ডাটাবেসে একটি টেবিল রয়েছে, এতে কোনও কী / বাধা নেই এবং একই মানগুলির সাথে একাধিক সারি রয়েছে।

আমি সমস্ত সদৃশ অপসারণ করতে এবং প্রতিটি সারির কেবল 1 টি অনুলিপি রাখতে চাই।

বিশেষত একটি কলাম রয়েছে (নামযুক্ত "কী") যা সদৃশ সনাক্তকরণের জন্য ব্যবহৃত হতে পারে (অর্থাত্ প্রতিটি স্বতন্ত্র "কী" এর জন্য কেবল একটি প্রবেশিকা উপস্থিত থাকতে হবে)।

কিভাবে আমি এটি করতে পারব? (আদর্শভাবে একটি একক এসকিউএল কমান্ড সহ) গতি এই ক্ষেত্রে কোনও সমস্যা নয় (কেবলমাত্র কয়েকটি সারি রয়েছে)।

উত্তর:


80
DELETE FROM dupes a
WHERE a.ctid <> (SELECT min(b.ctid)
                 FROM   dupes b
                 WHERE  a.key = b.key);

20
এটি ব্যবহার করবেন না, এটি খুব ধীর!
পাওয়ে মলিসাক

5
যদিও এই সমাধানটি অবশ্যই কাজ করে, নীচে @rapimo এর সমাধানটি আরও দ্রুত কার্যকর করে utes আমি বিশ্বাস করি যে অন্যান্য সমাধানে চলছে এমন গ্রুপিংয়ের পরিবর্তে এখানে অভ্যন্তরীণ নির্বাচনের বিবৃতিটি N বার (ডুপস টেবিলের সমস্ত এন সারিগুলির জন্য) কার্যকর করা হবে।
ডেভিড

বিশাল টেবিলগুলির জন্য (কয়েক মিলিয়ন রেকর্ড) এটি @ রপিমোর সমাধানের বিপরীতে মেমরির সাথে আসলে ফিট করে। সুতরাং এই ক্ষেত্রে এটি দ্রুততর (কোনও অদলবদল নয়)।
জিয়েল

1
ব্যাখ্যা যুক্ত করা হচ্ছে: এটি কাজ করে কারণ সিটিডি একটি বিশেষ পোস্টগ্রাস কলাম যা সারির শারীরিক অবস্থান নির্দেশ করে। আপনার টেবিলটিতে কোনও অনন্য আইডি না থাকলেও আপনি এটি অনন্য আইডি হিসাবে ব্যবহার করতে পারেন। postgresql.org/docs/8.2/ddl-
সিস্টেমে- কলামগুলি

194

একটি দ্রুত সমাধান হয়

DELETE FROM dups a USING (
      SELECT MIN(ctid) as ctid, key
        FROM dups 
        GROUP BY key HAVING COUNT(*) > 1
      ) b
      WHERE a.key = b.key 
      AND a.ctid <> b.ctid

20
এটি কেন_ ঘোড়া_ও_না_নামের সমাধানের চেয়ে দ্রুত?
রবার্তো

3
এটি দ্রুততর কারণ এটি কেবল 2 টি ক্যোয়ারী চালায়। সমস্ত অনুলিপি নির্বাচন করতে প্রথমে একটি, তারপরে টেবিল থেকে সমস্ত আইটেম মুছতে হবে। @A_horse_with_no_name এর ক্যোয়ারীটি টেবিলের প্রতিটি আইটেমের সাথে এটির সাথে অন্য কোনওটির সাথে মেলে কিনা তা দেখার জন্য একটি কোয়েরি করে।
আইওলুন

5
কি ctid?
টেককুজ

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

1
2 টির বেশি সদৃশ সারি থাকা অবস্থায় এটি কাজ করে না বলে মনে হয়, কারণ এটি সময়ে কেবল একটি অনুলিপি মুছে দেয়।
ফ্রাঙ্কি ড্রেক

73

এটি দ্রুত এবং সংক্ষিপ্ত:

DELETE FROM dupes T1
    USING   dupes T2
WHERE   T1.ctid < T2.ctid  -- delete the older versions
    AND T1.key  = T2.key;  -- add more columns if needed

অনন্য সনাক্তকারী ছাড়া ডুপ্লিকেট সারিগুলি কীভাবে মুছবেন সে সম্পর্কে আমার উত্তরও দেখুন যাতে আরও তথ্য রয়েছে।


সিটি কি জন্য দাঁড়ায়? গণনা?
টেককুজ

4
@trthrtz ctidসারণীতে রেকর্ডের শারীরিক অবস্থানের দিকে ইঙ্গিত করে। মন্তব্যে আমি এই সময়ে যা লিখেছি তার বিপরীতে অপারেটরের চেয়ে কম ব্যবহার করা পুরানো সংস্করণের দিকে আবশ্যক নয় কারণ সিটি চারপাশে মোড়ানো করতে পারে এবং নিম্ন সিটিডের সাথে মানটি আরও নতুন হতে পারে।
ইসাপির

1
শুধু এফওয়াইআই, আমি এই সমাধানটি চেষ্টা করেছি এবং 15 মিনিট অপেক্ষা করার পরে এটি বাতিল করে দিয়েছি। র‌্যাপিমোর সমাধানটি চেষ্টা করে এবং এটি প্রায় 10 সেকেন্ডে শেষ হয়েছিল (~ 700,000 সারি মুছে ফেলা হয়েছে)।
প্যাট্রিক

@ পেট্রিক কল্পনা করতে পারবেন না যে আপনার ডিবিতে কোনও অনন্য সনাক্তকারী নেই কারণ র‌্যাপিমোর উত্তর সে ক্ষেত্রে কার্যকর হয় না।
stucash

@ আইসাপির আমি কি উত্সাহী, উপরের উত্তরগুলি, তারা নির্বাচিত হওয়ার সাথে সাথে তারা পুরানো রেকর্ডগুলি ঠিক রাখছে min(ctid)? আপনার নতুন নতুন রাখা হয়? ধন্যবাদ!
16:59

17

আমি এটি চেষ্টা করেছি:

DELETE FROM tablename
WHERE id IN (SELECT id
              FROM (SELECT id,
                             ROW_NUMBER() OVER (partition BY column1, column2, column3 ORDER BY id) AS rnum
                     FROM tablename) t
              WHERE t.rnum > 1);

পোস্টগ্রিস উইকি সরবরাহ করেছেন:

https://wiki.postgresql.org/wiki/Deleting_duplicates


@ রপিমোর উত্তর এবং স্বীকৃত একটি (@ a_horse_with_no_name) এর সাথে তুলনা করে পারফরম্যান্সের কোনও ধারণা?
tuxayo

3
যদি প্রশ্নগুলির বিবরণগুলির মতো সমস্ত কলামগুলি অভিন্ন, idঅন্তর্ভুক্ত থাকে তবে এইটি কার্যকর হবে না ।
ইবিজামান

এই ক্যোয়ারী মূল অনুলিপি এবং সদৃশ উভয়ই মুছে ফেলবে। প্রশ্নটি কমপক্ষে একটি সারি ধরে রাখার বিষয়ে।
পাইবম্ব

@PYBomb ভুল, এটি idকলাম 1 ... 3 টি সদৃশ যেখানে প্রথম থাকবে
জেফ

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

7

আমার নিজের সংস্করণটি তৈরি করতে হয়েছিল। @A_horse_with_no_name দ্বারা লিখিত সংস্করণটি আমার টেবিলের (21M সারি) খুব ধীরে ধীরে। এবং @rapimo কেবল ডুপগুলি মুছবে না।

পোস্টগ্র্রেএসকিউএল 9.5 এ আমি যা ব্যবহার করি তা এখানে

DELETE FROM your_table
WHERE ctid IN (
  SELECT unnest(array_remove(all_ctids, actid))
  FROM (
         SELECT
           min(b.ctid)     AS actid,
           array_agg(ctid) AS all_ctids
         FROM your_table b
         GROUP BY key1, key2, key3, key4
         HAVING count(*) > 1) c);

6

আমি একটি অস্থায়ী টেবিল ব্যবহার করব:

create table tab_temp as
select distinct f1, f2, f3, fn
  from tab;

তারপর, মুছুন tabএবং নামান্তর tab_tempমধ্যে tab


8
এই পদ্ধতিটি ট্রিগার, সূচক এবং পরিসংখ্যানগুলির জন্য অ্যাকাউন্ট করে না। অবশ্যই আপনি এগুলি যোগ করতে পারেন, তবে এটি আরও অনেক কাজ যুক্ত করে।
জর্ডান

প্রত্যেকেরই এর প্রয়োজন হয় না। এই পদ্ধতিটি অত্যন্ত দ্রুত এবং সূচি ছাড়াই 200 কে ইমেলের (বার্তা 250) এর চেয়ে অনেক ভাল কাজ করেছে।
সের্গেই তেলশেভস্কি

পূর্ণ কোড:DROP TABLE IF EXISTS tmp; CREATE TABLE tmp as ( SELECT * from (SELECT DISTINCT * FROM your_table) as t ); DELETE from your_table; INSERT INTO your_table SELECT * from tmp; DROP TABLE tmp;
এরিক বুরেল

1

idকলাম দ্বারা সমস্ত অনন্য আইডির সন্ধান এবং অনন্য তালিকায় নেই এমন অন্যান্য আইডিগুলি সরাতে অন্য পদ্ধতির (কেবলমাত্র যদি আপনার টেবিলের মতো কোনও অনন্য ক্ষেত্র থাকে তবেই কাজ করে )

DELETE
FROM users
WHERE users.id NOT IN (SELECT DISTINCT ON (username, email) id FROM users);

বিষয়টি হল, আমার প্রশ্নে টেবিলগুলির কোনও অনন্য আইড ছিল না; "অনুলিপিগুলি" হ'ল একাধিক সারি যা সমস্ত কলামে ঠিক একই মান সহ।
আন্দ্রে মুরুজিয়াও

ঠিক আছে, আমি কিছু নোট যুক্ত করেছি
জায়টসেভ দিমিত্রি

1

কেমন:

সঙ্গে
  আপনি যেমন (আপনার_তালিকা থেকে বিচ্ছিন্ন নির্বাচন করুন),
  এক্স এএস (আপনার_তালিকা থেকে মুছে ফেলুন)
আপনার_সারণী নির্বাচন করুন * থেকে প্রবেশ করুন;

আমি মৃত্যুদন্ড কার্যকর করার আদেশ সম্পর্কে উদ্বিগ্ন ছিলাম, নির্বাচন নির্ধারণের আগে ডিলিটটি ঘটবে তবে তা আমার পক্ষে ঠিক কাজ করে। এবং টেবিল কাঠামো সম্পর্কে কোনও জ্ঞানের প্রয়োজন না থাকার যুক্ত বোনাস রয়েছে।


একমাত্র ত্রুটিটি হ'ল, যদি আপনার কাছে এমন ডেটা টাইপ থাকে যা সমতা সমর্থন করে না (উদাহরণস্বরূপ json) এটি কাজ করবে না।
a_horse_with_no_name

0

এটি আমার পক্ষে ভাল কাজ করেছে। আমার একটি টেবিল ছিল, শর্তাবলী, যাতে সদৃশ মান রয়েছে। সমস্ত সদৃশ সারি দিয়ে একটি টেম্প টেবিল তৈরি করতে একটি ক্যোয়ারী চালান। তারপরে আমি টেম্প টেবিলের আইডির সাথে মুছে ফেলার বিবরণটি চালিয়েছি। মান হ'ল কলামটি যাতে নকল থাকে।

        CREATE TEMP TABLE dupids AS
        select id from (
                    select value, id, row_number() 
over (partition by value order by value) 
    as rownum from terms
                  ) tmp
                  where rownum >= 2;

delete from [table] where id in (select id from dupids)

0

এখানে একটি সমাধান ব্যবহার করে PARTITION BY:

DELETE FROM dups
USING (
  SELECT
    ctid,
    (ctid != min(ctid) OVER (PARTITION BY key_column1, key_column2 [...])) AS is_duplicate
  FROM dups 
) dups_find_duplicates
WHERE dups.ctid == dups_find_duplicates.ctid
AND dups_find_duplicates.is_duplicate
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.