Bagaimana saya bisa menghapus baris duplikat?

1285

Apa cara terbaik untuk menghapus duplikat baris dari SQL Servertabel yang cukup besar (yaitu 300.000+ baris)?

Baris, tentu saja, tidak akan menjadi duplikat yang sempurna karena keberadaan RowIDbidang identitas.

MyTable

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null
Seibar
sumber
13
Kiat cepat untuk pengguna PostgreSQL yang membaca ini (banyak, berdasarkan seberapa sering dikaitkan): Pg tidak memaparkan istilah CTE sebagai tampilan yang dapat diperbarui sehingga Anda tidak dapat DELETE FROMlangsung menggunakan istilah CTE. Lihat stackoverflow.com/q/18439054/398670
Craig Ringer
@CraigRinger hal yang sama berlaku untuk Sybase - Saya telah mengumpulkan solusi yang tersisa di sini (harus berlaku untuk PG dan lainnya, juga: stackoverflow.com/q/19544489/1855801 (cukup ganti ROWID()fungsi dengan kolom RowID, jika ada)
maf-soft
12
Hanya untuk menambahkan peringatan di sini. Saat menjalankan proses de-duplikasi, selalu periksa kembali apa yang Anda hapus terlebih dahulu! Ini adalah salah satu area di mana sangat umum untuk secara tidak sengaja menghapus data yang baik.
Jeff Davis

Jawaban:

1142

Dengan asumsi tidak ada nulls, Anda GROUP BYkolom yang unik, dan SELECTyang MIN (or MAX)RowId sebagai baris untuk menjaga. Lalu, hapus saja semua yang tidak memiliki id baris:

DELETE FROM MyTable
LEFT OUTER JOIN (
   SELECT MIN(RowId) as RowId, Col1, Col2, Col3 
   FROM MyTable 
   GROUP BY Col1, Col2, Col3
) as KeepRows ON
   MyTable.RowId = KeepRows.RowId
WHERE
   KeepRows.RowId IS NULL

Jika Anda memiliki GUID dan bukan bilangan bulat, Anda bisa menggantinya

MIN(RowId)

dengan

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))
Mark Brackett
sumber
327
Apakah ini akan berhasil juga? DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);
Georg Schölly
10
@Andriy - Dalam SQL Server LEFT JOINkurang efisien daripada NOT EXISTS sqlinthewild.co.za/index.php/2010/03/23/... Situs yang sama juga membandingkan NOT INvs NOT EXISTS. sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in Keluar dari 3 saya pikir NOT EXISTSberkinerja terbaik. Ketiganya akan menghasilkan rencana dengan bergabung sendiri meskipun itu dapat dihindari.
Martin Smith
12
@ Martin, @ Georg: Jadi, saya sudah melakukan tes kecil. Sebuah tabel besar dibuat dan diisi seperti yang dijelaskan di sini: sqlinthewild.co.za/index.php/2010/03/23/... Dua SELECT kemudian diproduksi, satu menggunakan LEFT JOIN + WHERE IS NULL, yang lain menggunakan NOT Jadi satu. Kemudian saya melanjutkan dengan rencana eksekusi, dan coba tebak? Biaya kueri 18% untuk LEFT JOIN melawan 82% untuk NOT IN, kejutan besar bagi saya. Saya mungkin telah melakukan sesuatu yang seharusnya tidak saya lakukan atau sebaliknya, yang, jika benar, saya benar-benar ingin tahu.
Andriy M
16
@ GeorgSchölly telah memberikan jawaban yang elegan. Saya telah menggunakannya pada tabel di mana bug PHP saya membuat baris duplikat.
Philip Kearns
12
Maaf tapi mengapa DELETE MyTable FROM MyTablesintaksinya benar? Saya tidak melihat meletakkan nama tabel tepat setelah DELETEopsi dalam dokumentasi di sini . Maaf jika ini jelas bagi orang lain; Saya seorang pemula untuk SQL hanya mencoba untuk belajar. Lebih penting daripada mengapa itu bekerja: apa perbedaan antara termasuk nama tabel di sana atau tidak?
levininja
760

Cara lain yang memungkinkan untuk melakukan ini adalah

; 

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

Saya menggunakan di ORDER BY (SELECT 0)atas karena sewenang-wenang baris yang harus dipertahankan jika terjadi seri.

Untuk mempertahankan yang terbaru RowIDagar misalnya Anda dapat menggunakanORDER BY RowID DESC

Rencana Eksekusi

Rencana pelaksanaan untuk ini sering kali lebih sederhana dan lebih efisien daripada yang ada di jawaban yang diterima karena tidak memerlukan self join.

Rencana Eksekusi

Namun ini tidak selalu terjadi. Satu tempat di mana GROUP BYsolusi mungkin lebih disukai adalah situasi di mana agregat hash akan dipilih dalam preferensi untuk agregat aliran.

The ROW_NUMBERsolusi akan selalu memberikan cukup banyak rencana yang sama sedangkan GROUP BYstrategi lebih fleksibel.

Rencana Eksekusi

Faktor-faktor yang mungkin mendukung pendekatan agregat hash adalah

  • Tidak ada indeks berguna pada kolom partisi
  • kelompok yang relatif lebih sedikit dengan duplikat yang relatif lebih banyak di setiap kelompok

Dalam versi ekstrem dari kasus kedua ini (jika ada sangat sedikit grup dengan masing-masing duplikat di masing-masing) orang juga dapat mempertimbangkan hanya dengan memasukkan baris untuk disimpan ke dalam tabel baru kemudian TRUNCATE-ing yang asli dan menyalinnya kembali untuk meminimalkan logging dibandingkan dengan menghapus sebuah proporsi baris yang sangat tinggi.

Martin Smith
sumber
28
Jika saya dapat menambahkan: Jawaban yang diterima tidak bekerja dengan tabel yang digunakan uniqueidentifier. Yang ini jauh lebih sederhana dan bekerja dengan sempurna di meja mana pun. Terima kasih Martin.
BrunoLM
15
Ini jawaban yang luar biasa! Itu bekerja ketika saya telah menghapus PK lama sebelum saya menyadari ada duplikat di sana. +100
Mikael Eliasson
12
Saya sarankan bertanya dan kemudian menjawab pertanyaan ini (dengan jawaban ini) di DBA.SE. Kemudian kita dapat menambahkannya ke daftar jawaban kanonik kita .
Nick Chammas
16
Tidak seperti jawaban yang diterima, ini juga berfungsi pada tabel yang tidak memiliki kunci ( RowId) untuk dibandingkan.
vossad01
8
Yang satu ini tidak bekerja pada semua versi SQL server, di sisi lain
David
150

Ada artikel bagus tentang menghapus duplikat di situs Dukungan Microsoft. Ini cukup konservatif - mereka membuat Anda melakukan semuanya dalam langkah-langkah terpisah - tetapi harus bekerja dengan baik terhadap tabel besar.

Saya telah menggunakan self-joins untuk melakukan ini di masa lalu, meskipun mungkin bisa dilengkapi dengan klausa HAVING:

DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField 
AND dupes.secondDupField = fullTable.secondDupField 
AND dupes.uniqueField > fullTable.uniqueField
Jon Galloway
sumber
sempurna! saya menemukan ini adalah cara paling efisien untuk menghapus baris duplikat pada mariadb lama saya versi 10.1.xx. Terima kasih!
Drunken M
Jauh lebih sederhana dan mudah dipahami!
Marc
98

Permintaan berikut berguna untuk menghapus baris duplikat. Tabel dalam contoh ini memiliki IDsebagai kolom identitas dan kolom yang memiliki data duplikat adalah Column1, Column2dan Column3.

DELETE FROM TableName
WHERE  ID NOT IN (SELECT MAX(ID)
                  FROM   TableName
                  GROUP  BY Column1,
                            Column2,
                            Column3
                  /*Even if ID is not null-able SQL Server treats MAX(ID) as potentially
                    nullable. Because of semantics of NOT IN (NULL) including the clause
                    below can simplify the plan*/
                  HAVING MAX(ID) IS NOT NULL) 

Penggunaan script berikut menunjukkan dari GROUP BY, HAVING, ORDER BYdalam satu query, dan kembali hasil dengan duplikat kolom dan jumlah nya.

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC 
gngolakia
sumber
1
Kesalahan MySQL dengan skrip pertama 'Anda tidak dapat menentukan tabel target' TableName 'untuk pembaruan dalam klausa FROM'
D.Rosado
Terlepas dari kesalahan D.Rosado sudah dilaporkan, permintaan pertama Anda juga sangat lambat. Permintaan SELECT yang sesuai memakan setup saya + - 20 kali lebih lama dari jawaban yang diterima.
parvus
8
@parvus - Pertanyaan ini ditandai dengan SQL Server bukan MySQL. Sintaksnya baik-baik saja di SQL Server. Juga MySQL terkenal buruk dalam mengoptimalkan sub-query lihat contohnya di sini . Jawaban ini baik di SQL Server. Bahkan NOT INseringkali berkinerja lebih baik daripada OUTER JOIN ... NULL. Saya akan menambahkan HAVING MAX(ID) IS NOT NULLke permintaan meskipun meskipun semantik itu tidak perlu karena dapat meningkatkan contoh
Martin Smith
2
Berfungsi bagus di PostgreSQL 8.4.
nortally
63
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
SoftwareGeek
sumber
Mengapa mengirim solusi Postgres pada pertanyaan SQL Server?
Lankymart
2
@Lankymart Karena pengguna postgres juga datang ke sini. Lihatlah skor jawaban ini.
Gabriel
2
Saya telah melihat ini dalam beberapa pertanyaan SQL populer, seperti di sini , di sini dan di sini . OP mendapat jawabannya dan semua orang juga mendapat bantuan. Tidak masalah IMHO.
Gabriel
44
DELETE LU 
FROM   (SELECT *, 
               Row_number() 
                 OVER ( 
                   partition BY col1, col1, col3 
                   ORDER BY rowid DESC) [Row] 
        FROM   mytable) LU 
WHERE  [row] > 1 
Jithin Shaji
sumber
1
Saya mendapatkan pesan ini di azure SQL DW: Klausa FROM saat ini tidak didukung dalam pernyataan DELETE.
Amit
40

Ini akan menghapus baris duplikat, kecuali baris pertama

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

Lihat ( http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server )

Syed Mohamed
sumber
10
Untuk mysql akan memberikan kesalahan: Kode Kesalahan: 1093. Anda tidak dapat menentukan tabel target 'Mytable' untuk pembaruan dalam klausa FROM. tetapi perubahan kecil ini akan berfungsi untuk mysql: HAPUS DARI Mytable DI MANA Rowid TIDAK DALAM (SELECT ID FROM (SELECT MIN (RowID) SEBAGAI ID DARI GROUP Mytable OLEH Col1, Col2, Col3) SEBAGAI TEMP)
Ritesh
35

Saya lebih suka CTE untuk menghapus duplikat baris dari tabel sql server

sangat menyarankan untuk mengikuti artikel ini :: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

dengan menjaga yang asli

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

tanpa menyimpan yang asli

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)
Shamseer K
sumber
24

Untuk Mengambil Baris Duplikat:

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

Untuk Menghapus Baris Duplikat:

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      
Shaini Sinha
sumber
Untuk pengguna MySQL, perhatikan bahwa pertama-tama harus DELETE FROM, kedua, itu tidak akan berfungsi, karena Anda tidak bisa SELECTdari tabel yang sama dengan tempat Anda DELETEberasal. Di MySQL ini meledak MySQL error 1093.
Íhor Mé
23

Cepat dan Kotor untuk menghapus baris duplikat yang tepat (untuk tabel kecil):

select  distinct * into t2 from t1;
delete from t1;
insert into t1 select *  from t2;
drop table t2;
Juan Jo
sumber
3
Perhatikan bahwa pertanyaan sebenarnya menentukan duplikasi yang tidak tepat (dueto row id).
Dennis Jaheruddin
21

Saya lebih suka solusi subquery \ having count (*)> 1 untuk inner join karena saya merasa lebih mudah dibaca dan sangat mudah untuk berubah menjadi pernyataan SELECT untuk memverifikasi apa yang akan dihapus sebelum Anda menjalankannya.

--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
--)
James Errico
sumber
Bukankah itu menghapus semua catatan yang muncul di kueri batin. Kami hanya perlu menghapus duplikat dan menyimpan yang asli.
Sandy
3
Anda hanya mengembalikan yang dengan id terendah, berdasarkan min (id) di klausa pilih.
James Errico
2
Batalkan komentar pada baris pertama, kedua, dan terakhir dari kueri.
James Errico
7
Ini tidak akan membersihkan semua duplikat. Jika Anda memiliki 3 baris yang merupakan duplikat, itu hanya akan memilih baris dengan MIN (id), dan menghapus yang satu, meninggalkan dua baris tersisa yang merupakan duplikat.
Chloe
2
Namun demikian, saya akhirnya menggunakan pernyataan ini berulang-ulang, sehingga benar-benar membuat kemajuan alih-alih waktu koneksi habis atau komputer tidur. Saya mengubahnya MAX(id)untuk menghilangkan duplikat yang terakhir, dan ditambahkan LIMIT 1000000ke permintaan batin sehingga tidak harus memindai seluruh tabel. Ini menunjukkan kemajuan yang jauh lebih cepat daripada jawaban lain, yang tampaknya akan bertahan berjam-jam. Setelah tabel dipangkas ke ukuran yang bisa dikelola, maka Anda bisa menyelesaikan dengan kueri lainnya. Kiat: pastikan col1 / col2 / col3 memiliki indeks untuk grup oleh.
Chloe
17
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable
heta77
sumber
5
Memotong tidak akan berfungsi jika Anda memiliki referensi kunci asing ke myTable.
Sameer Alibhai
15

Saya pikir saya akan membagikan solusi saya karena ini bekerja dalam keadaan khusus. Saya kasus saya tabel dengan nilai duplikat tidak memiliki kunci asing (karena nilai-nilai itu digandakan dari db lain).

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!!

PS: ketika mengerjakan hal-hal seperti ini saya selalu menggunakan transaksi, ini tidak hanya memastikan semuanya dieksekusi secara keseluruhan, tetapi juga memungkinkan saya untuk menguji tanpa mempertaruhkan apapun. Tapi tentu saja Anda harus mengambil cadangan pula hanya untuk memastikan ...

Ruben Verschueren
sumber
14

Permintaan ini menunjukkan kinerja yang sangat baik untuk saya:

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

itu menghapus baris 1M dalam sedikit lebih dari 30detik dari tabel 2M (50% duplikat)

Draško
sumber
14

Menggunakan CTE. Idenya adalah untuk bergabung pada satu atau lebih kolom yang membentuk catatan duplikat dan kemudian menghapus mana yang Anda suka:

;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;
Ostati
sumber
1
Saya pikir Anda kehilangan DAN di GABUNG.
Justin R.
13

Namun solusi mudah lainnya dapat ditemukan di tautan yang ditempelkan di sini . Ini mudah dipahami dan tampaknya efektif untuk sebagian besar masalah serupa. Ini untuk SQL Server, tetapi konsep yang digunakan lebih dari dapat diterima.

Berikut adalah bagian yang relevan dari halaman yang ditautkan:

Pertimbangkan data ini:

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

Jadi bagaimana kita bisa menghapus data duplikat itu?

Pertama, masukkan kolom identitas dalam tabel itu dengan menggunakan kode berikut:

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

Gunakan kode berikut untuk mengatasinya:

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 
Nitish Pareek
sumber
1
"Mudah dipahami", "tampaknya efektif", tetapi tidak sepatah kata pun tentang apa yang termasuk dalam metode tersebut. Bayangkan saja tautannya menjadi tidak valid, lalu apa gunanya mengetahui bahwa metode itu mudah dipahami dan efektif? Silakan pertimbangkan untuk menambahkan bagian-bagian penting dari deskripsi metode ke dalam posting Anda, jika tidak ini bukan jawaban.
Andriy M
Metode ini berguna untuk tabel di mana Anda belum memiliki identitas yang ditentukan. Seringkali Anda perlu menyingkirkan duplikat untuk menentukan kunci utama!
Jeff Davis
@ JeffDavis - ROW_NUMBERVersi berfungsi dengan baik untuk kasus itu tanpa perlu menambahkan kolom baru sebelum Anda mulai.
Martin Smith
12

Berikut ini adalah artikel bagus lainnya tentang menghapus duplikat .

Ini membahas mengapa ini sulit: " SQL didasarkan pada aljabar relasional, dan duplikat tidak dapat terjadi dalam aljabar relasional, karena duplikat tidak diperbolehkan dalam satu set. "

Solusi tabel temp, dan dua contoh mysql.

Di masa depan Anda akan mencegahnya di tingkat basis data, atau dari perspektif aplikasi. Saya akan menyarankan tingkat database karena database Anda harus bertanggung jawab untuk menjaga integritas referensial, pengembang hanya akan menimbulkan masalah;)

Craig
sumber
1
SQL didasarkan pada multi-set. Tetapi bahkan jika itu didasarkan pada set, dua tupel (1, a) & (2, a) ini berbeda.
Andrew
12

Tentu Gunakan tabel temp. Jika Anda menginginkan pernyataan tunggal yang tidak terlalu berkinerja "berhasil", Anda dapat menggunakan:

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)

Pada dasarnya, untuk setiap baris dalam tabel, sub-pilih menemukan RowID atas semua baris yang persis seperti baris yang dipertimbangkan. Jadi, Anda berakhir dengan daftar RowID yang mewakili baris "asli" yang tidak terduplikasi.

Jacob Proffitt
sumber
11

Saya punya meja di mana saya harus menjaga baris non-duplikat. Saya tidak yakin dengan kecepatan atau efisiensinya.

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )
chrismar035
sumber
7
Ini mengasumsikan bahwa ada paling banyak 1 duplikat.
Martin Smith
Mengapa tidak HAVING COUNT(*) > 1?
Philipp M
11

Gunakan ini

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
Haris
sumber
10

Cara lainnya adalah Buat tabel baru dengan bidang yang sama dan dengan Indeks Unik . Kemudian pindahkan semua data dari tabel lama ke tabel baru . Secara otomatis SQL SERVER abaikan (ada juga opsi tentang apa yang harus dilakukan jika akan ada nilai duplikat: abaikan, interupsi, atau sth) nilai duplikat. Jadi kami memiliki tabel yang sama tanpa baris duplikat. Jika Anda tidak ingin Indeks Unik, setelah transfer data Anda dapat menjatuhkannya .

Khusus untuk tabel yang lebih besar, Anda dapat menggunakan DTS (paket SSIS untuk mengimpor / mengekspor data) untuk mentransfer semua data dengan cepat ke tabel baru yang diindeks unik. Untuk 7 juta baris dibutuhkan hanya beberapa menit.

İsmail Yavuz
sumber
9

Dengan menggunakan kueri di bawah ini, kami dapat menghapus rekaman duplikat berdasarkan satu kolom atau beberapa kolom. kueri di bawah ini dihapus berdasarkan pada dua kolom. nama tabel adalah: testingdan nama kolomempno,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)
Sudhakar NV
sumber
9
  1. Buat tabel kosong baru dengan struktur yang sama

  2. Jalankan query seperti ini

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) > 1
  3. Kemudian jalankan query ini

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) = 1
shA.t
sumber
9

Ini adalah cara termudah untuk menghapus catatan duplikat

 DELETE FROM tblemp WHERE id IN 
 (
  SELECT MIN(id) FROM tblemp
   GROUP BY  title HAVING COUNT(id)>1
 )

http://askme.indianyouth.info/details/how-to-dumplicate-record-from-table-in-using-sql-105

Harikesh Yadav
sumber
Mengapa ada orang yang tidak mendukung ini? Jika Anda memiliki lebih dari dua id yang sama, ini TIDAK AKAN berfungsi. Alih-alih menulis: hapus dari tblemp di mana id tidak berada di (pilih min (id) dari grup tblemp dengan judul)
crellee
7

Saya akan menyebutkan pendekatan ini juga karena dapat membantu, dan bekerja di semua server SQL: Cukup sering hanya ada satu - dua duplikat, dan Id serta jumlah duplikat dikenal. Pada kasus ini:

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

Dari level aplikasi (sayangnya). Saya setuju bahwa cara yang tepat untuk mencegah duplikasi adalah pada tingkat basis data melalui penggunaan indeks unik, tetapi dalam SQL Server 2005, indeks diperbolehkan hanya 900 byte, dan bidang varchar (2048) saya pukulan itu.

Saya tidak tahu seberapa baik kinerjanya, tapi saya pikir Anda bisa menulis pemicu untuk menegakkan ini, bahkan jika Anda tidak bisa melakukannya secara langsung dengan indeks. Sesuatu seperti:

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

Juga, varchar (2048) kedengarannya mencurigakan bagi saya (beberapa hal dalam hidup adalah 2048 bytes, tetapi sangat jarang); bukankah seharusnya itu varchar (maks)?

DrPizza
sumber
7

Cara lain untuk melakukan ini: -

DELETE A
FROM   TABLE A,
       TABLE B
WHERE  A.COL1 = B.COL1
       AND A.COL2 = B.COL2
       AND A.UNIQUEFIELD > B.UNIQUEFIELD 
yuvi
sumber
Apa yang berbeda dari jawaban yang ada ini dari 20 Agustus 2008? - stackoverflow.com/a/18934/692942
Lankymart
7
DELETE
FROM
    table_name T1
WHERE
    rowid > (
        SELECT
            min(rowid)
        FROM
            table_name T2
        WHERE
            T1.column_name = T2.column_name
    );
Teena
sumber
Halo Teena, Anda telah melewatkan tabel nama Alice T1 setelah menghapus komentar jika tidak maka akan melalui pengecualian sintaks.
Nagaraj M
6
CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int)

INSERT INTO car(PersonId,CarId)
VALUES(1,2),(1,3),(1,2),(2,4)

--SELECT * FROM car

;WITH CTE as(
SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car)

DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)
AnandPhadke
sumber
6

Saya ingin mempratinjau baris yang akan Anda hapus dan tetap mengontrol yang mana dari baris duplikat yang akan disimpan. Lihat 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
Lauri Lubi
sumber