এসকিউএল কোয়েরি: সর্বশেষ এন বাদে টেবিল থেকে সমস্ত রেকর্ড মুছবেন?


90

সর্বশেষ এন (আইডি ডেস্ক অনুসারে বাছাই করা) বাদে টেবিল থেকে সমস্ত রেকর্ড সরিয়ে ফেলতে কী একক মাইএসকিএল কোয়েরি (ভেরিয়েবল ছাড়াই) তৈরি করা সম্ভব?

এরকম কিছু, কেবল এটি কাজ করে না :)

delete from table order by id ASC limit ((select count(*) from table ) - N)

ধন্যবাদ

উত্তর:


140

আপনি সেইভাবে রেকর্ডগুলি মুছতে পারবেন না, মূল সমস্যাটি হ'ল আপনি একটি লিমিটেড ধারাটির মান নির্দিষ্ট করতে সাবকিয়ারিটি ব্যবহার করতে পারবেন না।

এটি কাজ করে (মাইএসকিউএল 5.0.67 এ পরীক্ষিত):

DELETE FROM `table`
WHERE id NOT IN (
  SELECT id
  FROM (
    SELECT id
    FROM `table`
    ORDER BY id DESC
    LIMIT 42 -- keep this many records
  ) foo
);

অন্তর্বর্তী subquery হয় প্রয়োজন। এটি ছাড়া আমরা দুটি ত্রুটিতে দৌড়াতে চাই:

  1. এসকিউএল ত্রুটি (1093): আপনি এফআরএম ধারাটিতে আপডেটের জন্য লক্ষ্য টেবিল 'টেবিল' নির্দিষ্ট করতে পারবেন না - মাইএসকিউএল আপনি যে টেবিলটি সরাসরি উপকণার মধ্যে থেকে মুছে ফেলছেন তা উল্লেখ করার অনুমতি দেয় না।
  2. এসকিউএল ত্রুটি (1235): মাইএসকিউএলের এই সংস্করণটি এখনও 'লিমিটেড এবং ইন / সমস্ত / কোনও / কোনও উপকৌড়া' সমর্থন করে না - আপনি কোনও নট ইন অপারেটরের প্রত্যক্ষ সাবকোয়ারির মধ্যে লিমিটেড ধারাটি ব্যবহার করতে পারবেন না।

ভাগ্যক্রমে, একটি মধ্যবর্তী subquery ব্যবহার আমাদের এই উভয় সীমাবদ্ধতা বাইপাস করতে পারবেন।


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


4
ঠিক আছে যে কাজ করে - তবে আমার কাছে, এটির মতো আরকেন ট্রিক্স অবলম্বন করা অসম্পূর্ণ এবং অসন্তুষ্টিজনক। তবুও উত্তরের জন্য +1।
বিল কারভিন

4
আমি এটি একটি গ্রহণযোগ্য উত্তর হিসাবে চিহ্নিত করি, কারণ এটি যা চেয়েছিল তা করে। তবে আমি ব্যক্তিগতভাবে এটি সম্ভবত সহজ রাখতে দুটি প্রশ্নে এটি করব :) আমি ভেবেছিলাম সম্ভবত কিছু দ্রুত এবং সহজ উপায় আছে।
সার্জ

4
ধন্যবাদ অ্যালেক্স, আপনার উত্তর আমাকে সাহায্য করেছে। আমি দেখছি যে মধ্যবর্তী subquery প্রয়োজন হয় কিন্তু আমি বুঝতে পারি না কেন। আপনি কি তার জন্য ব্যাখ্যা আছে?
এসভি 1

8
একটি প্রশ্ন: "ফু" কিসের জন্য?
সেবাস্তিয়ান ব্রেইট

9
পেরোলোকো, আমি ফাঁকি না দিয়ে চেষ্টা করেছি এবং এই ত্রুটিটি পেয়েছি: ত্রুটি 1248 (42000): প্রতিটি উত্সযুক্ত টেবিলের অবশ্যই তার নিজস্ব নাম থাকতে হবে তাই আমাদের উত্তরটি তাদের, প্রতিটি উত্সযুক্ত টেবিলের অবশ্যই তার নিজস্ব উপকরণ থাকতে হবে!
কোডিগম্যান

106

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

যে সমাধানগুলি আসলে কাজ করেছিল তা হ'ল অ্যালেক্স ব্যারেটের ডাবল সাব-কোয়েরি /NOT IN পদ্ধতি ( বিল কারভিনের অনুরূপ ), এবং কাসনোইয়েরLEFT JOIN পদ্ধতি।

দুর্ভাগ্যক্রমে উপরোক্ত দুটি পদ্ধতিই খুব বড় মধ্যবর্তী অস্থায়ী সারণী তৈরি করে এবং কার্যকারিতা দ্রুত হ্রাস পায় কারণ মুছে ফেলা হচ্ছে না এমন রেকর্ডের সংখ্যা বৃহত্তর হয়।

অ্যালেক্স ব্যারেটের ডাবল সাব-কোয়েরি (ধন্যবাদ!) ব্যবহারের ক্ষেত্রে আমি যা স্থির করেছি তা <=পরিবর্তে ব্যবহার করে NOT IN:

DELETE FROM `test_sandbox`
  WHERE id <= (
    SELECT id
    FROM (
      SELECT id
      FROM `test_sandbox`
      ORDER BY id DESC
      LIMIT 1 OFFSET 42 -- keep this many records
    ) foo
  )

এটি এন-র রেকর্ডের OFFSETআইডি পেতে ব্যবহার করে এবং সেই রেকর্ড এবং সমস্ত পূর্ববর্তী রেকর্ড মুছে দেয়।

যেহেতু অর্ডার করা ইতিমধ্যে এই সমস্যাটির একটি অনুমান ( ORDER BY id DESC), <=এটি একটি উপযুক্ত ফিট fit

এটি আরও দ্রুত, যেহেতু সাবকুই দ্বারা উত্পন্ন অস্থায়ী সারণীতে এন রেকর্ডগুলির পরিবর্তে কেবল একটি রেকর্ড রয়েছে ।

পরীক্ষা ক্ষেত্রে

দুটি পরীক্ষার ক্ষেত্রে আমি তিনটি কার্য পদ্ধতি এবং উপরের নতুন পদ্ধতিটি পরীক্ষা করেছি।

উভয় পরীক্ষার ক্ষেত্রে 10000 বিদ্যমান সারি ব্যবহার করা হয়, যখন প্রথম পরীক্ষাটি 9000 রাখে (সবচেয়ে পুরানো 1000 কে মুছে দেয়) এবং দ্বিতীয় পরীক্ষায় 50 রাখে (সবচেয়ে প্রাচীন 9950 মুছে দেয়)।

+-----------+------------------------+----------------------+
|           | 10000 TOTAL, KEEP 9000 | 10000 TOTAL, KEEP 50 |
+-----------+------------------------+----------------------+
| NOT IN    |         3.2542 seconds |       0.1629 seconds |
| NOT IN v2 |         4.5863 seconds |       0.1650 seconds |
| <=,OFFSET |         0.0204 seconds |       0.1076 seconds |
+-----------+------------------------+----------------------+

মজার বিষয় হ'ল <=পদ্ধতিটি বোর্ড জুড়ে আরও ভাল পারফরম্যান্স দেখায়, তবে আসলে খারাপের পরিবর্তে আপনি যত বেশি রাখবেন তা আরও ভাল হয়।


11
আমি 4.5 বছর পরে আবার এই থ্রেডটি পড়ছি। চমৎকার সংযোজন!
অ্যালেক্স ব্যারেট

বাহ, মহান এই মনে হচ্ছে কিন্তু মাইক্রোসফট SQL 2008 সালে কাজ করে না আমি এই বার্তা পেতে: " 'সীমা' কাছাকাছি ভুল বাক্য গঠন এটা এর চমৎকার এটি মাইএসকিউএল কাজ করে, কিন্তু আমি একটি বিকল্প সমাধান খুঁজে বের করার প্রয়োজন
কেন পামার

4
@KenPalmer আপনি এখনও একটি নির্দিষ্ট সারি এটি করতে সক্ষম হওয়া উচিত ব্যবহার অফসেট ROW_NUMBER(): stackoverflow.com/questions/603724/...
নিকলে

4
@ কেনপালমার এসকিউএল এবং মাইএসকিউএল
আলফা জি 33 কে

4
তার জন্য চিয়ার্স এটি আমার (খুব বড়) ডেটা সেটগুলিতে ক্যোয়ারিকে 12 মিনিট থেকে 3.64 সেকেন্ডে হ্রাস করেছে!
Lieuwe

10

দুর্ভাগ্যবশত সব অন্যান্য লোকেরা কর্তৃক প্রদত্ত, তুমি পারবে না উত্তরের জন্য DELETEএবং SELECTএকই ক্যোয়ারীতে একটি প্রদত্ত টেবিল থেকে।

DELETE FROM mytable WHERE id NOT IN (SELECT MAX(id) FROM mytable);

ERROR 1093 (HY000): You can't specify target table 'mytable' for update 
in FROM clause

অথবা মাইএসকিউএল LIMITকোনও উপকণায় সমর্থন করতে পারে না । এগুলি মাইএসকিউএল এর সীমাবদ্ধতা।

DELETE FROM mytable WHERE id NOT IN 
  (SELECT id FROM mytable ORDER BY id DESC LIMIT 1);

ERROR 1235 (42000): This version of MySQL doesn't yet support 
'LIMIT & IN/ALL/ANY/SOME subquery'

আমি যে উত্তম উত্তরটি সামনে আসতে পারি তা হ'ল এটি দুটি পর্যায়ে করা:

SELECT id FROM mytable ORDER BY id DESC LIMIT n; 

আইডি সংগ্রহ করুন এবং সেগুলি কমা দ্বারা পৃথক করা স্ট্রিংয়ে পরিণত করুন:

DELETE FROM mytable WHERE id NOT IN ( ...comma-separated string... );

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

দ্রষ্টব্য: যদিও এটি একটি একক ক্যোয়ারিতে কাজটি সেরে উঠছে না, তবে কখনও কখনও আরও সহজ, করণীয় সমাধানটি সবচেয়ে কার্যকর।


তবে আপনি একটি মুছুন এবং নির্বাচন করুন এর মধ্যে অভ্যন্তরীণ যোগদান করতে পারেন। আমি নীচে যা করেছি তা কাজ করা উচিত।
অচিনদা 99

সাবকিউরিতে কাজ করতে সীমাবদ্ধ করার জন্য আপনাকে মধ্যস্থতাকারী সাবকোয়ারি ব্যবহার করতে হবে।
অ্যালেক্স ব্যারেট

@ অচিনদা 99: আমি এই থ্রেডে আপনার কাছ থেকে কোনও উত্তর দেখছি না ...?
বিল কারভিন

আমি একটি সভার জন্য টানা পেয়েছিলাম। আমার খারাপ। আমি যে স্কেল লিখেছিলাম তা পরীক্ষা করার জন্য আমার এখনই পরীক্ষার পরিবেশ নেই, তবে অ্যালেক্স ব্যারেট যা করেছিলেন তা আমি উভয়ই করে ফেলেছি এবং এটি একটি অভ্যন্তরীণ যোগদানের সাথে কাজ করতে পেরেছি।
অচিনদা 99

এটি মাইএসকিউএল এর বোকামি সীমাবদ্ধতা। PostgreSQL সহ, দুর্দান্ত DELETE FROM mytable WHERE id NOT IN (SELECT id FROM mytable ORDER BY id DESC LIMIT 3);কাজ করে।
bortzmeyer


5

আপনার আইডি যদি ইনক্রিমেন্টাল হয় তবে এর মতো কিছু ব্যবহার করুন

delete from table where id < (select max(id) from table)-N

4
এই দুর্দান্ত কৌশলটিতে একটি বড় সমস্যা: সিরিয়ালগুলি সর্বদা সংঘবদ্ধ হয় না (উদাহরণস্বরূপ যখন রোলব্যাকগুলি ছিল)।
বোর্টজমায়ার

5

সর্বশেষ এন ব্যতীত সমস্ত রেকর্ড মুছতে আপনি নীচের প্রতিবেদন করা ক্যোয়ারীটি ব্যবহার করতে পারেন।

এটি একটি একক ক্যোয়ারী কিন্তু অনেক বিবৃতি দিয়ে তাই এটি আসলে না ক-এর একক ক্যোয়ারী উপায় এটা মূল প্রশ্নে জন্যই ছিল।

এছাড়াও মাইএসকিউএল বাগের কারণে আপনার একটি পরিবর্তনশীল এবং বিল্ট-ইন (ক্যোয়ারীতে) প্রস্তুত বিবৃতি প্রয়োজন need

আশা করি এটি যেভাবেই কার্যকর হতে পারে ...

NNN সারি করছে রাখা এবং theTable টেবিল আপনি কাজ করছি হয়।

আমি ধরে নিচ্ছি আপনার আইডি নামের একটি স্বতঃসংশোধন রেকর্ড রয়েছে

SELECT @ROWS_TO_DELETE := COUNT(*) - nnn FROM `theTable`;
SELECT @ROWS_TO_DELETE := IF(@ROWS_TO_DELETE<0,0,@ROWS_TO_DELETE);
PREPARE STMT FROM "DELETE FROM `theTable` ORDER BY `id` ASC LIMIT ?";
EXECUTE STMT USING @ROWS_TO_DELETE;

এই পদ্ধতির সম্পর্কে ভাল জিনিসটি হল পারফরম্যান্স : আমি স্থানীয় এক ডিবিতে প্রায় ১৩,০০০ রেকর্ড রেখে ক্যোরিটি পরীক্ষা করেছি, সর্বশেষ ১,০০০ রেখেছি। এটি 0.08 সেকেন্ডে চলে।

গৃহীত উত্তর থেকে স্ক্রিপ্ট ...

DELETE FROM `table`
WHERE id NOT IN (
  SELECT id
  FROM (
    SELECT id
    FROM `table`
    ORDER BY id DESC
    LIMIT 42 -- keep this many records
  ) foo
);

0.55 সেকেন্ড সময় নেয়। প্রায় 7 গুণ বেশি।

পরীক্ষার পরিবেশ: এসএসডি সহ ২০১১ i7 ম্যাকবুকপ্রো এর শেষের দিকে মাইএসকিউএল 5.5.25



1

কোয়েরির নীচে চেষ্টা করুন:

DELETE FROM tablename WHERE id < (SELECT * FROM (SELECT (MAX(id)-10) FROM tablename ) AS a)

অভ্যন্তরীণ সাব কোয়েরিটি শীর্ষ 10 মান প্রদান করবে এবং বহিরাগত কোয়েরিটি শীর্ষ 10 বাদে সমস্ত রেকর্ড মুছে ফেলবে।


4
এই উত্তরটি জুড়ে যারা আসেন তাদের পক্ষে এই কাজগুলি কীভাবে উপকারী হবে সে সম্পর্কে কিছু ব্যাখ্যা। কোড ডাম্পিং সাধারণত সুপারিশ করা হয় না।
রেআরিং

সামঞ্জস্যপূর্ণ আইডি না দিয়ে এটি সঠিক নয়
স্লাভা রোজনেভ

0

কি সম্পর্কে :

SELECT * FROM table del 
         LEFT JOIN table keep
         ON del.id < keep.id
         GROUP BY del.* HAVING count(*) > N;

এটি আগের চেয়ে N সারির চেয়ে আরও বেশি সারি সারি দেয়। দরকারী হতে পারে?


0

এই কাজের জন্য আইডি ব্যবহার করা অনেক ক্ষেত্রে কোনও বিকল্প নয়। উদাহরণস্বরূপ - টুইটার স্ট্যাটাস সহ টেবিল। নির্দিষ্ট টাইমস্ট্যাম্প ক্ষেত্র সহ এখানে একটি বৈকল্পিক।

delete from table 
where access_time >= 
(
    select access_time from  
    (
        select access_time from table 
            order by access_time limit 150000,1
    ) foo    
)

0

মাইক্রোসফ্টের পরিবর্তে মাইক্রোসফ্ট এসকিউএল সার্ভার ব্যবহার করে এমন কারও জন্য এটি মিশ্রণে ফেলে দিতে চেয়েছিল। 'সীমা' শব্দটি এমএসএসকিউএল দ্বারা সমর্থিত নয়, সুতরাং আপনাকে একটি বিকল্প ব্যবহার করতে হবে। এই কোডটি এসকিউএল ২০০৮ এ কাজ করেছিল এবং এই এসও পোস্টের উপর ভিত্তি করে। https://stackoverflow.com/a/1104447/993856

-- Keep the last 10 most recent passwords for this user.
DECLARE @UserID int; SET @UserID = 1004
DECLARE @ThresholdID int -- Position of 10th password.
SELECT  @ThresholdID = UserPasswordHistoryID FROM
        (
            SELECT ROW_NUMBER()
            OVER (ORDER BY UserPasswordHistoryID DESC) AS RowNum, UserPasswordHistoryID
            FROM UserPasswordHistory
            WHERE UserID = @UserID
        ) sub
WHERE   (RowNum = 10) -- Keep this many records.

DELETE  UserPasswordHistory
WHERE   (UserID = @UserID)
        AND (UserPasswordHistoryID < @ThresholdID)

স্বীকার করা, এটি মার্জিত নয়। আপনি যদি মাইক্রোসফ্ট এসকিউএল এর জন্য এটি অনুকূল করতে সক্ষম হন তবে দয়া করে আপনার সমাধানটি ভাগ করুন। ধন্যবাদ!


0

আপনার যদি অন্য কিছু কলামের উপর ভিত্তি করে রেকর্ডগুলিও মুছতে হয়, তবে এখানে একটি সমাধান দেওয়া হয়েছে:

DELETE
FROM articles
WHERE id IN
    (SELECT id
     FROM
       (SELECT id
        FROM articles
        WHERE user_id = :userId
        ORDER BY created_at DESC LIMIT 500, 10000000) abc)
  AND user_id = :userId

0

এটি পাশাপাশি কাজ করা উচিত:

DELETE FROM [table] 
INNER JOIN (
    SELECT [id] 
    FROM (
        SELECT [id] 
        FROM [table] 
        ORDER BY [id] DESC
        LIMIT N
    ) AS Temp
) AS Temp2 ON [table].[id] = [Temp2].[id]


-1

কেন না

DELETE FROM table ORDER BY id DESC LIMIT 1, 123456789

দ্বিতীয় LIMIT- আর্গুমেন্ট হিসাবে খুব খুব বড় সংখ্যাটি ব্যবহার করে, প্রথম সারিতে (অর্ডারটি ডিইএসসি!) ব্যতীত কেবল সমস্ত মুছুন। এখানে দেখো


4
DELETEসমর্থন করে না [offset],বা OFFSET: dev.mysql.com/doc/refman/5.0/en/delete.html
নিকোল

-1

দীর্ঘ সময় পরে এর উত্তর দেওয়া ... একই পরিস্থিতি জুড়ে এসে উল্লিখিত উত্তরগুলি ব্যবহার করার পরিবর্তে আমি নীচে নিয়ে এসেছি -

DELETE FROM table_name order by ID limit 10

এটি প্রথম 10 টি রেকর্ড মুছে ফেলবে এবং সর্বশেষ রেকর্ডগুলি রাখবে।


প্রশ্নটি "সমস্ত শেষ এন রেকর্ডগুলি পেরেছিল" এবং "একটি একক প্রশ্নে" জিজ্ঞাসা করেছিল। তবে মনে হয় এখনও টেবিলের সমস্ত রেকর্ড গণনা করার জন্য আপনার এখনও প্রথম জিজ্ঞাসা দরকার - এন
পাওলো

@ পাওলো আমাদের সমস্ত রেকর্ড গণনা করার জন্য কোনও জিজ্ঞাসার প্রয়োজন নেই কারণ উপরের ক্যোয়ারীটি গত 10 টি রেকর্ড বাদে সমস্ত মুছে ফেলে।
নীতেশ

4
না, এই ক্যোয়ারীটি 10 ​​পুরানো রেকর্ড মুছে ফেলে। ওপি সর্বশেষতম রেকর্ডগুলি বাদে সবকিছু মুছতে চায়। আপনার হল একটি মৌলিক সমাধান যা একটি গণনা প্রশ্নের সাথে যুক্ত করা হবে, যখন ওপি জিজ্ঞাসা করছে যে কোনও কিছুর মধ্যে সমস্ত কিছু একত্রিত করার উপায় আছে কি না asking
ক্রিসমল

@ ক্রিসমল আমি একমত আমি কি এখনই এই উত্তরটি সম্পাদনা / মুছে ফেলব যা ব্যবহারকারীরা আমাকে ভোট না দেয় বা এটি যেমনটি ছেড়ে দেয়?
নীতেশ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.