Làm thế nào tôi có thể loại bỏ các hàng trùng lặp?


1285

Cách tốt nhất để xóa các hàng trùng lặp khỏi một SQL Serverbảng khá lớn (tức là hơn 300.000 hàng) là gì?

Các hàng, tất nhiên, sẽ không phải là bản sao hoàn hảo vì sự tồn tại của trường RowIDdanh tính.

MyTable

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

13
Mẹo nhanh cho người dùng PostgreSQL đọc điều này (rất nhiều, theo mức độ thường xuyên được liên kết đến): PG không hiển thị các thuật ngữ CTE dưới dạng xem có thể cập nhật để bạn không thể DELETE FROMtrực tiếp sử dụng thuật ngữ CTE. Xem stackoverflow.com/q/18439054/398670
Craig Ringer

@CraigRinger cũng đúng với Sybase - Tôi đã thu thập các giải pháp còn lại ở đây (cũng hợp lệ cho PG và các giải pháp khác: stackoverflow.com/q/19544361/1855801 (chỉ cần thay thế ROWID()chức năng bằng cột RowID, nếu có)
maf-soft

12
Chỉ cần thêm một cảnh báo ở đây. Khi chạy bất kỳ quá trình sao chép nào, luôn luôn kiểm tra lại những gì bạn đang xóa trước tiên! Đây là một trong những lĩnh vực rất phổ biến để vô tình xóa dữ liệu tốt.
Jeff Davis

Câu trả lời:


1142

Giả sử không null, bạn GROUP BYcột độc đáo, và SELECTcác MIN (or MAX)ROWID như hàng giữ. Sau đó, chỉ cần xóa mọi thứ không có id hàng:

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

Trong trường hợp bạn có GUID thay vì số nguyên, bạn có thể thay thế

MIN(RowId)

với

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))

327
Điều này sẽ làm việc như là tốt? DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);
Georg Schölly

10
@Andriy - Trong SQL Server LEFT JOINkém hiệu quả hơn NOT EXISTS sqlinthewild.co.za/index.php/2010/03/23/NH Cùng một trang web cũng so sánh NOT INvới NOT EXISTS. sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in Trong số 3 tôi nghĩ hoạt động NOT EXISTStốt nhất. Cả ba sẽ tạo ra một kế hoạch với sự tự tham gia mặc dù điều đó có thể tránh được.
Martin Smith

12
@Martin, @Georg: Vì vậy, tôi đã thực hiện một thử nghiệm nhỏ. Một bảng lớn đã được tạo và được điền như mô tả ở đây: sqlinthewild.co.za/index.php/2010/03/23/ Từ Hai CHỌN sau đó đã được tạo, một sử dụng kỹ thuật LEFT THAM GIA + WHERE LÀ NULL, còn lại sử dụng kỹ thuật KHÔNG Trong một. Sau đó, tôi đã tiến hành các kế hoạch thực hiện, và đoán những gì? Chi phí truy vấn là 18% cho LEFT THAM GIA so với 82% cho KHÔNG VÀO, một bất ngờ lớn đối với tôi. Tôi có thể đã làm một cái gì đó tôi không nên có hoặc ngược lại, nếu đúng, tôi thực sự muốn biết.
Andriy M

16
@ GeorgSchölly đã cung cấp một câu trả lời thanh lịch. Tôi đã sử dụng nó trên một bảng trong đó một lỗi PHP của tôi đã tạo ra các hàng trùng lặp.
Philip Kearns

12
Xin lỗi nhưng tại sao lại DELETE MyTable FROM MyTableđúng cú pháp? Tôi không thấy việc đặt tên bảng ngay sau DELETEtùy chọn trong tài liệu ở đây . Xin lỗi nếu điều này là rõ ràng với người khác; Tôi là người mới chơi SQL chỉ đang cố gắng học. Quan trọng hơn là tại sao nó hoạt động: sự khác biệt giữa bao gồm tên của bảng ở đó hay không?
levininja

760

Một cách khác có thể làm điều này là

; 

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

Tôi đang sử dụng ORDER BY (SELECT 0)ở trên vì nó là tùy ý hàng nào để bảo quản trong trường hợp hòa.

Để bảo quản cái mới nhất RowIDđể lấy ví dụ bạn có thể sử dụngORDER BY RowID DESC

Kế hoạch thực hiện

Kế hoạch thực hiện cho việc này thường đơn giản và hiệu quả hơn so với câu trả lời được chấp nhận vì nó không yêu cầu tự tham gia.

Kế hoạch thực hiện

Điều này không phải lúc nào cũng đúng. Một nơi mà GROUP BYgiải pháp có thể được ưu tiên là các tình huống trong đó tổng hợp băm sẽ được chọn theo sở thích đối với tổng hợp luồng.

Các ROW_NUMBERgiải pháp sẽ luôn luôn cung cấp cho khá nhiều kế hoạch tương tự trong khi GROUP BYchiến lược là linh hoạt hơn.

Kế hoạch thực hiện

Các yếu tố có thể ủng hộ cách tiếp cận tổng hợp băm sẽ là

  • Không có chỉ mục hữu ích trên các cột phân vùng
  • các nhóm tương đối ít hơn với các bản sao tương đối nhiều hơn trong mỗi nhóm

Trong các phiên bản cực đoan của trường hợp thứ hai này (nếu có rất ít nhóm có nhiều nhóm trùng lặp), người ta cũng có thể xem xét đơn giản là chèn các hàng để giữ vào một bảng mới sau đó - TRUNCATEsao chép bản gốc và sao chép chúng để giảm thiểu ghi nhật ký so với xóa tỷ lệ rất cao của các hàng.


28
Nếu tôi có thể thêm: Câu trả lời được chấp nhận không hoạt động với các bảng sử dụng uniqueidentifier. Điều này là đơn giản hơn nhiều và hoạt động hoàn hảo trên bất kỳ bảng. Cảm ơn Martin.
BrunoLM

15
Đây là một câu trả lời tuyệt vời! Nó hoạt động sự kiện khi tôi đã loại bỏ PK cũ trước khi tôi nhận ra nơi đó trùng lặp. +100
Mikael Eliasson

12
Tôi đề nghị hỏi và sau đó trả lời câu hỏi này (với câu trả lời này) trên DBA.SE. Sau đó, chúng tôi có thể thêm nó vào danh sách các câu trả lời kinh điển của chúng tôi .
Nick Chammas

16
Không giống như câu trả lời được chấp nhận, điều này cũng hoạt động trên một bảng không có khóa ( RowId) để so sánh.
vossad01

8
Điều này không hoạt động trên tất cả các phiên bản máy chủ SQL, mặt khác
David

150

Có một bài viết hay về loại bỏ trùng lặp trên trang web Hỗ trợ của Microsoft. Điều đó khá bảo thủ - họ yêu cầu bạn làm mọi thứ theo các bước riêng biệt - nhưng nó sẽ hoạt động tốt với các bảng lớn.

Tôi đã sử dụng tự tham gia để làm điều này trong quá khứ, mặc dù nó có thể được sử dụng với mệnh đề HAVING:

DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField 
AND dupes.secondDupField = fullTable.secondDupField 
AND dupes.uniqueField > fullTable.uniqueField

hoàn hảo! tôi thấy đây là cách hiệu quả nhất để xóa các hàng trùng lặp trên phiên bản mariadb cũ 10.1.xx. cảm ơn bạn!
Drunken M

Đơn giản và dễ hiểu hơn nhiều!
Marc

98

Các truy vấn sau đây là hữu ích để xóa các hàng trùng lặp. Bảng trong ví dụ này có IDnhư một cột sắc và các cột có dữ liệu trùng lặp là Column1, Column2Column3.

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) 

Các chương trình kịch bản sau đây sử dụng GROUP BY, HAVING, ORDER BYtrong một truy vấn, và trả về kết quả với cột trùng lặp và tính của nó.

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC 

1
Lỗi MySQL với tập lệnh đầu tiên 'Bạn không thể chỉ định bảng đích' Tên bảng 'để cập nhật trong mệnh đề TỪ'
D.Rosado

Ngoài lỗi D.Rosado đã được báo cáo, truy vấn đầu tiên của bạn cũng rất chậm. Truy vấn SELECT tương ứng mất trên thiết lập của tôi + - 20 lần so với câu trả lời được chấp nhận.
parvus

8
@parvus - Câu hỏi được gắn thẻ SQL Server không phải MySQL. Cú pháp tốt trong SQL Server. Ngoài ra, MySQL nổi tiếng là xấu trong việc tối ưu hóa các truy vấn phụ xem ví dụ ở đây . Câu trả lời này là tốt trong SQL Server. Trong thực tế NOT INthường thực hiện tốt hơn OUTER JOIN ... NULL. Tôi sẽ thêm một HAVING MAX(ID) IS NOT NULLtruy vấn mặc dù về mặt ngữ nghĩa, nó không cần thiết vì điều đó có thể cải thiện ví dụ về
Martin Smith

2
Hoạt động tuyệt vời trong PostgreSQL 8.4.
miền bắc

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

Hậu kỳ:

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

Tại sao đăng giải pháp Postgres trên câu hỏi SQL Server?
Lankymart

2
@Lankymart Vì người dùng postgres cũng đến đây. Nhìn vào điểm số của câu trả lời này.
Gabriel

2
Tôi đã thấy điều này trong một số câu hỏi SQL phổ biến, như ở đây , đâyđây . OP đã nhận được câu trả lời của anh ấy và mọi người khác cũng nhận được sự giúp đỡ. Không có vấn đề 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 

1
Tôi nhận được thông báo này trên azure SQL DW: Mệnh đề TỪ hiện không được hỗ trợ trong câu lệnh XÓA.
Amit

40

Điều này sẽ xóa các hàng trùng lặp, ngoại trừ hàng đầu tiên

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

Tham khảo ( http://www.codeproject.com/Articles/157977/Remove-Dsplate-Rows-from-a-Table-in-Query-Server )


10
Đối với mysql, nó sẽ báo lỗi: Mã lỗi: 1093. Bạn không thể chỉ định bảng mục tiêu 'Mytable' để cập nhật trong mệnh đề TỪ. nhưng sự thay đổi nhỏ này sẽ làm việc cho mysql: DELETE FROM MyTable ĐÂU ROWID logic NOT IN (SELECT ID FROM (SELECT MIN (ROWID) AS ID TỪ MyTable GROUP BY col1, col2, Col3) AS TEMP)
Ritesh

35

Tôi muốn CTE xóa các hàng trùng lặp khỏi bảng máy chủ sql

đặc biệt khuyên bạn nên theo dõi bài viết này :: http://codaffection.com/sql-server-article/delete-d repeatate -rows-in-sql-server /

bằng cách giữ bản gốc

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

mà không giữ bản gốc

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)

24

Để tìm nạp các hàng trùng lặp:

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

Để xóa các hàng trùng lặp:

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

Đối với người dùng MySQL, lưu ý rằng trước hết phải là DELETE FROM, thứ hai, nó sẽ không hoạt động, bởi vì bạn không thể SELECTtừ cùng một bảng mà bạn đang sử dụng DELETE. Trong MySQL này nổ tung MySQL error 1093.
Íhor Mé

23

Nhanh và bẩn để xóa các hàng trùng lặp chính xác (đối với các bảng nhỏ):

select  distinct * into t2 from t1;
delete from t1;
insert into t1 select *  from t2;
drop table t2;

3
Lưu ý rằng câu hỏi thực sự chỉ định sao chép không chính xác (id hàng dueto).
Dennis Jaheruddin 16/07/2015

21

Tôi thích giải pháp truy vấn con \ có tính (*)> 1 cho phép nối bên trong vì tôi thấy nó dễ đọc hơn và rất dễ biến thành câu lệnh CHỌN để xác minh những gì sẽ bị xóa trước khi bạn chạy nó.

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

Nó không xóa tất cả các bản ghi hiển thị trong truy vấn bên trong. Chúng ta cần loại bỏ chỉ trùng lặp và bảo tồn bản gốc.
Sandy

3
Bạn chỉ trả về cái có id thấp nhất, dựa trên min (id) trong mệnh đề select.
James Errico

2
Bỏ ghi chú dòng đầu tiên, thứ hai và cuối cùng của truy vấn.
James Errico

7
Điều này sẽ không làm sạch tất cả các bản sao. Nếu bạn có 3 hàng trùng lặp, nó sẽ chỉ chọn hàng có MIN (id) và xóa hàng đó, để lại hai hàng còn lại là trùng lặp.
Chloe

2
Tuy nhiên, tôi đã kết thúc việc sử dụng câu lệnh này lặp đi lặp lại nhiều lần, để nó thực sự đạt được tiến bộ thay vì hết thời gian kết nối hoặc máy tính chuyển sang chế độ ngủ. Tôi đã thay đổi nó để MAX(id)loại bỏ các bản sao sau và thêm vào LIMIT 1000000truy vấn bên trong để nó không phải quét toàn bộ bảng. Điều này cho thấy tiến độ nhanh hơn nhiều so với các câu trả lời khác, dường như sẽ bị treo trong nhiều giờ. Sau khi bảng được cắt theo kích thước có thể quản lý, sau đó bạn có thể kết thúc với các truy vấn khác. Mẹo: đảm bảo col1 / col2 / col3 có các chỉ số cho nhóm theo.
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

5
Cắt bớt sẽ không hoạt động nếu bạn có các tham chiếu khóa ngoài đến myTable.
Sameer Alibhai

15

Tôi nghĩ tôi sẽ chia sẻ giải pháp của mình vì nó hoạt động trong những trường hợp đặc biệt. Trường hợp của tôi, bảng có các giá trị trùng lặp không có khóa ngoại (vì các giá trị được sao chép từ một db khác).

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

Tái bút: khi làm việc trên những thứ như thế này tôi luôn sử dụng một giao dịch, điều này không chỉ đảm bảo mọi thứ được thực hiện một cách tổng thể, mà còn cho phép tôi kiểm tra mà không gặp rủi ro gì. Nhưng tất nhiên, dù sao bạn cũng nên sao lưu chỉ để chắc chắn ...


14

Truy vấn này cho thấy hiệu suất rất tốt đối với tôi:

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

nó đã xóa các hàng 1M trong ít hơn 30 giây từ bảng 2M (50% trùng lặp)


14

Sử dụng CTE. Ý tưởng là tham gia vào một hoặc nhiều cột tạo thành một bản ghi trùng lặp và sau đó xóa bất cứ thứ gì bạn thích:

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

1
Tôi nghĩ rằng bạn đang thiếu một VÀ trong THAM GIA của bạn.
Justin R.

13

Tuy nhiên, một giải pháp dễ dàng khác có thể được tìm thấy tại liên kết được dán ở đây . Điều này dễ nắm bắt và dường như có hiệu quả đối với hầu hết các vấn đề tương tự. Nó dành cho SQL Server nhưng khái niệm được sử dụng là không thể chấp nhận được.

Dưới đây là các phần có liên quan từ trang được liên kết:

Xem xét dữ liệu này:

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

Vậy làm thế nào chúng ta có thể xóa những dữ liệu trùng lặp đó?

Đầu tiên, chèn một cột danh tính trong bảng đó bằng cách sử dụng mã sau đây:

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

Sử dụng mã sau đây để giải quyết nó:

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

1
"Dễ dàng để nắm bắt", "dường như có hiệu quả", nhưng không phải là một lời về những gì phương pháp này bao gồm trong. Chỉ cần tưởng tượng rằng các liên kết trở thành hợp lệ, những gì sử dụng sau đó sẽ được để biết rằng phương pháp này dễ dàng để nắm bắt và hiệu quả? Vui lòng xem xét thêm các phần thiết yếu của mô tả phương pháp vào bài đăng của bạn, nếu không đây không phải là câu trả lời.
Andriy M

Phương pháp này hữu ích cho các bảng mà bạn chưa xác định danh tính. Thường thì bạn cần loại bỏ các bản sao để xác định khóa chính!
Jeff Davis

@JeffDavis - ROW_NUMBERPhiên bản hoạt động tốt trong trường hợp đó mà không cần phải đi đến độ dài của việc thêm một cột mới trước khi bạn bắt đầu.
Martin Smith

12

Đây là một bài viết tốt về loại bỏ trùng lặp .

Nó thảo luận về lý do tại sao nó khó: " SQL dựa trên đại số quan hệ và các trùng lặp không thể xảy ra trong đại số quan hệ, bởi vì các trùng lặp không được phép trong một tập hợp. "

Giải pháp bảng tạm thời và hai ví dụ mysql.

Trong tương lai, bạn sẽ ngăn chặn nó ở cấp độ cơ sở dữ liệu hoặc từ góc độ ứng dụng. Tôi sẽ đề xuất mức cơ sở dữ liệu vì cơ sở dữ liệu của bạn phải chịu trách nhiệm duy trì tính toàn vẹn tham chiếu, các nhà phát triển sẽ gây ra sự cố;)


1
SQL dựa trên nhiều bộ. Nhưng ngay cả khi nó dựa trên các bộ, hai bộ dữ liệu này (1, a) & (2, a) là khác nhau.
Andrew

12

Ồ chắc chắn rồi. Sử dụng bảng tạm thời. Nếu bạn muốn một tuyên bố duy nhất, không thực hiện mà "hoạt động", bạn có thể đi với:

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)

Về cơ bản, đối với mỗi hàng trong bảng, phần chọn phụ tìm thấy RowID trên cùng của tất cả các hàng giống hệt như hàng đang xem xét. Vì vậy, bạn kết thúc với một danh sách các RowID đại diện cho các hàng không trùng lặp "ban đầu".


11

Tôi đã có một bảng nơi tôi cần để bảo tồn các hàng không trùng lặp. Tôi không chắc về tốc độ hay hiệu quả.

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

7
Điều này giả định rằng có nhiều nhất 1 bản sao.
Martin Smith

Tại sao không HAVING COUNT(*) > 1?
Philipp M

11

Dùng cái này

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

10

Một cách khác là Tạo một bảng mới với cùng các trường và với Chỉ mục duy nhất . Sau đó di chuyển tất cả dữ liệu từ bảng cũ sang bảng mới . Tự động SQL SERVER bỏ qua (cũng có một tùy chọn về việc cần làm nếu có giá trị trùng lặp: bỏ qua, ngắt hoặc sth) các giá trị trùng lặp. Vì vậy, chúng ta có cùng một bảng mà không có hàng trùng lặp. Nếu bạn không muốn Chỉ mục duy nhất, sau khi chuyển dữ liệu, bạn có thể xóa nó .

Đặc biệt đối với các bảng lớn hơn, bạn có thể sử dụng DTS (gói SSIS để nhập / xuất dữ liệu) để chuyển tất cả dữ liệu nhanh chóng sang bảng được lập chỉ mục duy nhất mới của bạn. Đối với 7 triệu hàng chỉ mất vài phút.


9

Bằng cách sử dụng truy vấn bên dưới, chúng tôi có thể xóa các bản ghi trùng lặp dựa trên một cột hoặc nhiều cột. bên dưới truy vấn đang xóa dựa trên hai cột. tên bảng là: testingvà tên cộtempno,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)

9
  1. Tạo bảng trống mới có cùng cấu trúc

  2. Thực hiện truy vấn như thế này

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) > 1
  3. Sau đó thực hiện truy vấn này

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) = 1

9

Đây là cách dễ nhất để xóa bản ghi trùng lặp

 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-USE-sql-105


Tại sao có ai ủng hộ điều này? Nếu bạn có nhiều hơn hai id giống nhau thì điều này sẽ không hoạt động. Thay vào đó hãy viết: xóa khỏi tblemp trong đó id không có trong (chọn min (id) từ nhóm tblemp theo tiêu đề)
crellee

7

Tôi sẽ đề cập đến cách tiếp cận này cũng như nó có thể hữu ích và hoạt động trong tất cả các máy chủ SQL: Khá thường chỉ có một - hai bản sao, Id và số lượng bản sao được biết đến. Trong trường hợp này:

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

7

Từ cấp độ ứng dụng (không may). Tôi đồng ý rằng cách thích hợp để ngăn chặn sự trùng lặp là ở cấp cơ sở dữ liệu thông qua việc sử dụng một chỉ mục duy nhất, nhưng trong SQL Server 2005, một chỉ mục được phép chỉ là 900 byte và trường varchar (2048) của tôi sẽ loại bỏ điều đó.

Tôi không biết nó sẽ hoạt động tốt như thế nào, nhưng tôi nghĩ bạn có thể viết một trình kích hoạt để thực thi điều này, ngay cả khi bạn không thể làm điều đó trực tiếp với một chỉ mục. Cái gì đó như:

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

Ngoài ra, varchar (2048) nghe có vẻ tanh với tôi (một số thứ trong cuộc sống là 2048 byte, nhưng nó khá hiếm); nó thực sự không nên là varchar (max)?


7

Một cách khác để làm điều này: -

DELETE A
FROM   TABLE A,
       TABLE B
WHERE  A.COL1 = B.COL1
       AND A.COL2 = B.COL2
       AND A.UNIQUEFIELD > B.UNIQUEFIELD 

Có gì khác với câu trả lời hiện có từ ngày 20 tháng 8 năm 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
    );

Xin chào Teena, bạn đã bỏ lỡ bảng Alice tên T1 sau khi xóa bình luận nếu không nó sẽ phá vỡ ngoại lệ cú pháp.
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)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.