sql server আমি কিভাবে ডুপ্লিকেট সারি মুছে ফেলতে পারি?




sql-server tsql (24)

একটি মোটামুটি বড় SQL Server টেবিল (অর্থাৎ 300,000+ সারি) থেকে সদৃশ সারি অপসারণ করার সেরা উপায় কি?

সারি, অবশ্যই, RowID পরিচয় ক্ষেত্রের অস্তিত্বের কারণে নিখুঁত সদৃশ হবে না।

MyTable

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null

এটা ব্যবহার কর

WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name)
   As RowNumber,* FROM <table_name>
)
DELETE FROM tblTemp where RowNumber >1

আমি SQL সার্ভার টেবিল থেকে সদৃশ সারি মুছে ফেলার জন্য CTE পছন্দ করব

দৃঢ়ভাবে এই নিবন্ধটি অনুসরণ করার সুপারিশ :: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

মূল পালন করে

WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN
FROM MyTable
)

DELETE FROM CTE WHERE RN<>1

মূল রাখা ছাড়া

WITH CTE AS
(SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3)
FROM MyTable)
 
DELETE CTE
WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)

delete t1
from table t1, table t2
where t1.columnA = t2.columnA
and t1.rowid>t2.rowid

Postgres:

delete
from table t1
using table t2
where t1.columnA = t2.columnA
and t1.rowid > t2.rowid

আমি বিশেষ পরিস্থিতিতে অধীনে কাজ করে আমি আমার সমাধান ভাগ চাই। আমি আমার ক্ষেত্রে ডুপ্লিকেট মান সহ টেবিল একটি বিদেশী কী ছিল না (কারণ মান অন্য ডিবি থেকে সদৃশ ছিল)।

begin transaction
-- create temp table with identical structure as source table
Select * Into #temp From tableName Where 1 = 2

-- insert distinct values into temp
insert into #temp 
select distinct * 
from  tableName

-- delete from source
delete from tableName 

-- insert into source from temp
insert into tableName 
select * 
from #temp

rollback transaction
-- if this works, change rollback to commit and execute again to keep you changes!!

পিএস: এই ধরনের জিনিসগুলিতে কাজ করার সময় আমি সর্বদা একটি লেনদেন ব্যবহার করি, এটি কেবল সবকিছুকে সম্পূর্ণরূপে নির্বাহিত করে তা নিশ্চিত করে না, তবে আমাকে কিছু ঝুঁকি ছাড়াই পরীক্ষা করার অনুমতি দেয়। কিন্তু অবশেষে নিশ্চিত হোন যে আপনি কোনও ব্যাকআপ নিতে পারেন ...


ওহ নিশ্চিত। একটি টেম্প টেবিল ব্যবহার করুন। যদি আপনি একটি একক, অসাধারণ অভিনয়কারী বিবৃতি চান যা "কাজ করে" তবে আপনি যেতে পারেন:

DELETE FROM MyTable WHERE NOT RowID IN
    (SELECT 
        (SELECT TOP 1 RowID FROM MyTable mt2 
        WHERE mt2.Col1 = mt.Col1 
        AND mt2.Col2 = mt.Col2 
        AND mt2.Col3 = mt.Col3) 
    FROM MyTable mt)

মূলত, টেবিলে প্রতিটি সারির জন্য, উপ-নির্বাচনটি সারির শীর্ষ সারিটি সারির সারির মতই থাকে যা ঠিক সারির মত। সুতরাং আপনি ROWID গুলির তালিকাটি শেষ করেন যা "আসল" নন-ডুপ্লিকেটযুক্ত সারির প্রতিনিধিত্ব করে।


আমি একটি টেবিল ছিল যেখানে আমি নন-ডুপ্লিকেট সারি সংরক্ষণ করতে হবে। আমি গতি বা দক্ষতা নিশ্চিত নই।

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )


DELETE LU 
FROM   (SELECT *, 
               Row_number() 
                 OVER ( 
                   partition BY col1, col1, col3 
                   ORDER BY rowid DESC) [Row] 
        FROM   mytable) LU 
WHERE  [row] > 1 

এটি প্রথম সারির ব্যতীত সদৃশ সারি মুছবে

DELETE
FROM
    Mytable
WHERE
    RowID NOT IN (
        SELECT
            MIN(RowID)
        FROM
            Mytable
        GROUP BY
            Col1,
            Col2,
            Col3
    )

পড়ুন ( http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server অপসারণ- ডুপ্লিকেট - রাউন্ড-থেকে- A- টেবিল- ইন- SQL- http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server )


আপনি যে সারিগুলি সরাতে চলেছেন তার পূর্বরূপ দেখতে চান এবং রাখা কোনও অনুলিপি সারিগুলিতে নিয়ন্ত্রণ রাখেন। http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/ দেখুন

with MYCTE as (
  SELECT ROW_NUMBER() OVER (
    PARTITION BY DuplicateKey1
                ,DuplicateKey2 -- optional
    ORDER BY CreatedAt -- the first row among duplicates will be kept, other rows will be removed
  ) RN
  FROM MyTable
)
DELETE FROM MYCTE
WHERE RN > 1

এই প্রশ্নের আমার জন্য খুব ভাল পারফরম্যান্স দেখিয়েছেন:

DELETE tbl
FROM
    MyTable tbl
WHERE
    EXISTS (
        SELECT
            *
        FROM
            MyTable tbl2
        WHERE
            tbl2.SameValue = tbl.SameValue
        AND tbl.IdUniqueValue < tbl2.IdUniqueValue
    )

এটি 2 এম (50% ডুপ্লিকেট) এর একটি টেবিলের থেকে 30 সেকেন্ডের মধ্যে 1 ম সারি মুছে ফেলেছে।


সিটিই ব্যবহার করে। ধারণাটি এমন একটি বা একাধিক কলামে যোগদান করা যা একটি সদৃশ রেকর্ড তৈরি করে এবং আপনি যা চান তা সরাতে পারেন:

;with cte as (
    select 
        min(PrimaryKey) as PrimaryKey
        UniqueColumn1,
        UniqueColumn2
    from dbo.DuplicatesTable 
    group by
        UniqueColumn1, UniqueColumn1
    having count(*) > 1
)
delete d
from dbo.DuplicatesTable d 
inner join cte on 
    d.PrimaryKey > cte.PrimaryKey and
    d.UniqueColumn1 = cte.UniqueColumn1 and 
    d.UniqueColumn2 = cte.UniqueColumn2;

SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable

অ্যাপ্লিকেশন স্তর থেকে (দুর্ভাগ্যবশত)। আমি সম্মত হচ্ছি যে ডুপ্লিকেশন প্রতিরোধের সঠিক উপায় একটি অনন্য সূচক ব্যবহারের মাধ্যমে ডাটাবেস স্তরের উপর, কিন্তু এসকিউএল সার্ভার 2005-এ, একটি সূচককে শুধুমাত্র 900 বাইটের অনুমতি দেওয়া হয় এবং আমার ভার্চার (২048) ক্ষেত্রটি এটিকে দূরে ফেলে দেয়।

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

-- given a table stories(story_id int not null primary key, story varchar(max) not null)
CREATE TRIGGER prevent_plagiarism 
ON stories 
after INSERT, UPDATE 
AS 
    DECLARE @cnt AS INT 

    SELECT @cnt = Count(*) 
    FROM   stories 
           INNER JOIN inserted 
                   ON ( stories.story = inserted.story 
                        AND stories.story_id != inserted.story_id ) 

    IF @cnt > 0 
      BEGIN 
          RAISERROR('plagiarism detected',16,1) 

          ROLLBACK TRANSACTION 
      END 

এছাড়াও, ভার্চার (২048) আমার কাছে ক্ষতিকারক শোনাচ্ছে (জীবনের কিছু জিনিস 2048 বাইট, তবে এটি বেশ অস্বাভাবিক); এটা কি সত্যিই ওয়ারচার না (সর্বোচ্চ)?


এখনো আরেকটি সহজ সমাধান http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server pasted লিঙ্ক পাওয়া http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server । এই সহজে বোঝার জন্য এবং একই ধরণের সমস্যার জন্য কার্যকর বলে মনে হচ্ছে। এটি যদিও এসকিউএল সার্ভারের জন্য কিন্তু ব্যবহৃত ধারণাটি গ্রহণযোগ্য নয়।

লিঙ্কযুক্ত পাতা থেকে প্রাসঙ্গিক অংশ এখানে রয়েছে:

এই তথ্য বিবেচনা করুন:

EMPLOYEE_ID ATTENDANCE_DATE
A001    2011-01-01
A001    2011-01-01
A002    2011-01-01
A002    2011-01-01
A002    2011-01-01
A003    2011-01-01

তাহলে আমরা কিভাবে সেই নকল তথ্য মুছে ফেলতে পারি?

প্রথম, নিম্নলিখিত কোড ব্যবহার করে যে টেবিলের একটি পরিচয় কলাম সন্নিবেশ করান:

ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)  

এটি সমাধানের জন্য নিচের কোডটি ব্যবহার করুন:

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 

আমি subquery \ count (*)> অভ্যন্তরীণ যোগের 1 টি সমাধান পছন্দ করি কারণ আমি এটি সহজ পড়তে পেয়েছি এবং এটি চালানোর আগে কী মুছে ফেলা হবে তা যাচাই করতে SELECT বিবৃতিতে পরিণত হওয়া খুব সহজ ছিল।

--DELETE FROM table1 
--WHERE id IN ( 
     SELECT MIN(id) FROM table1 
     GROUP BY col1, col2, col3 
     -- could add a WHERE clause here to further filter
     HAVING count(*) > 1
--)

DELETE
FROM
    table_name T1
WHERE
    rowid > (
        SELECT
            min(rowid)
        FROM
            table_name T2
        WHERE
            T1.column_name = T2.column_name
    );

অন্য উপায় একই ক্ষেত্র এবং অনন্য সূচক সঙ্গে একটি নতুন টেবিল তৈরি করা হয়। তারপরে পুরানো টেবিলে থেকে সমস্ত তথ্য নতুন টেবিলের দিকে সরান । স্বয়ংক্রিয়ভাবে এসকিউএল সার্ভার উপেক্ষা করে (যদি একটি সদৃশ মান থাকবে তবে কী করবেন তা সম্পর্কে একটি বিকল্প রয়েছে: উপেক্ষা, বিঘ্নিত বা sth) সদৃশ মান। সুতরাং আমরা অনুরূপ সারি ছাড়া একই টেবিল আছে। আপনি যদি স্বতন্ত্র ইন্ডেক্স চান না তবে ট্রান্সফার ডেটা পরে আপনি এটি ড্রপ করতে পারেন

বিশেষ করে বৃহত্তর টেবিলের জন্য আপনি আপনার নতুন অনন্য সূচীকৃত টেবিলে সমস্ত তথ্য দ্রুত হস্তান্তর করতে DTS (ডেটা আমদানি / রপ্তানি করতে এসএসআইএস প্যাকেজ) ব্যবহার করতে পারেন। 7 মিলিয়ন সারির জন্য এটি মাত্র কয়েক মিনিট সময় নেয়।


নীচের প্রশ্নের ব্যবহার করে আমরা একক কলাম বা একাধিক কলামের উপর ভিত্তি করে নকল রেকর্ড মুছে ফেলতে সক্ষম হতে পারি। নীচের কোয়েরি দুটি কলামের উপর ভিত্তি করে মুছে ফেলা হয়। টেবিল নামটি হল: testing এবং কলামের নাম empno,empname

DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
or empname not in
(select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)

এখানে সদৃশ অপসারণ একটি ভাল নিবন্ধ।

এটি কেন কঠিন তা নিয়ে আলোচনা করে: " এসকিউএল সম্পর্কযুক্ত বীজগণিতের উপর ভিত্তি করে, এবং সদৃশ সম্পর্কযুক্ত বীজগণিতের মধ্যে ঘটতে পারে না, কারণ একটি সেটে সদৃশ অনুমতি নেই। "

টেম্প টেবিল সমাধান, এবং দুটি MySQL উদাহরণ।

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


সদৃশ সারি আনতে:

SELECT
name, email, COUNT(*)
FROM 
users
GROUP BY
name, email
HAVING COUNT(*) > 1

সদৃশ সারি মুছতে:

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      

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

SET ROWCOUNT 1 -- or set to number of rows to be deleted
delete from myTable where RowId = DuplicatedID
SET ROWCOUNT 0

DELETE 
FROM MyTable
WHERE NOT EXISTS (
              SELECT min(RowID)
              FROM Mytable
              WHERE (SELECT RowID 
                     FROM Mytable
                     GROUP BY Col1, Col2, Col3
                     ))
               );

এই কাজ করার আরেকটি সম্ভাব্য উপায়

; 

--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 
                                       ORDER BY ( SELECT 0)) RN
         FROM   #MyTable)
DELETE FROM cte
WHERE  RN > 1;

আমি ORDER BY (SELECT 0) ব্যবহার করছি কারণ এটি অনির্ধারিত যা কোন টাই এর ইভেন্টে সংরক্ষণ করতে সারি।

RowID অর্ডারে RowID সংরক্ষণ করতে আপনি উদাহরণস্বরূপ ORDER BY RowID DESC ব্যবহার করতে পারেন

এক্সিকিউশন পরিকল্পনা

এই জন্য মৃত্যুদন্ড পরিকল্পনাটি প্রায়ই স্বতঃসিদ্ধ এবং স্বীকৃত উত্তরগুলির চেয়ে বেশি কার্যকরী হয় কারণ এটি স্ব যোগদানের প্রয়োজন হয় না।

এই তবে, সবসময় না. এক জায়গা যেখানে GROUP BY সমাধান পছন্দ করা যেতে পারে এমন পরিস্থিতি যেখানে একটি হ্যাশ সমষ্টি একটি স্ট্রিম সমষ্টিতে অগ্রাধিকারে চয়ন করা হবে।

ROW_NUMBER সমাধানটি সর্বদা একই প্ল্যানটি প্রদান করবে যখন GROUP BY কৌশল আরও বেশি নমনীয়।

হাশ সামগ্রিক পদ্ধতির পক্ষে হতে পারে এমন উপাদানগুলি হ'ল

  • বিভাজন কলামে কোন দরকারী সূচক নেই
  • অপেক্ষাকৃত কম গ্রুপ প্রতিটি গ্রুপে অপেক্ষাকৃত বেশি duplicates

এই দ্বিতীয় ক্ষেত্রে চরম সংস্করণগুলিতে (যদি প্রতিটিতে অনেকগুলি সদৃশ সহ খুব কম সংখ্যক গোষ্ঠী থাকে) তবে একটি নতুন টেবিলে রাখতে সারিগুলিকে কেবল সন্নিবেশ করাতে পারে এবং মূলত TRUNCATE এবং মোছার তুলনায় লগিং কমিয়ে আনতে তাদের অনুলিপি করা যেতে পারে। সারির একটি খুব উচ্চ অনুপাত।







duplicates