2012-06-21 55 views
5

Tôi đã mắc lỗi trong tập lệnh chèn số lượng lớn, vì vậy bây giờ tôi có các hàng "trùng lặp" với các colX khác nhau. Tôi cần phải xóa các hàng trùng lặp này, nhưng tôi không thể tìm ra cách. Để được chính xác hơn, tôi có điều này:Xóa các hàng "trùng lặp" trong SQL Server 2010

col1 | col2 | col3 | colX  
----+---------------------- 
    0 | 1 | 2 | a 
    0 | 1 | 2 | b 
    0 | 1 | 2 | c 
    0 | 1 | 2 | a 
    3 | 4 | 5 | x 
    3 | 4 | 5 | y 
    3 | 4 | 5 | x 
    3 | 4 | 5 | z 

và tôi muốn giữ sự xuất hiện đầu tiên của mỗi (hàng, colX):

col1 | col2 | col3 | colX  
----+---------------------- 
    0 | 1 | 2 | a 
    3 | 4 | 5 | x 

Cảm ơn bạn đã trả lời của bạn :)

+2

bảng cơ sở dữ liệu không có khái niệm về trật tự liên tiếp. Bạn có muốn sắp xếp theo phút (colX) và giữ các hàng đó không? Có cột dấu thời gian trên hàng không? –

+3

Bạn đang sử dụng phiên bản SQL Server nào? Theo như tôi biết, không có SQL Server 2010. –

+0

Nếu bạn có '0 | 1 | 3 | a' trên dữ liệu của bạn, nên được lưu giữ? hoặc nó nên được loại bỏ? –

Trả lời

10

Hãy thử phương pháp đơn giản nhất với CTE Sql Server: http://www.sqlfiddle.com/#!3/2d386/2

dữ liệu:

CREATE TABLE tbl 
    ([col1] int, [col2] int, [col3] int, [colX] varchar(1)); 

INSERT INTO tbl 
    ([col1], [col2], [col3], [colX]) 
VALUES 
    (0, 1, 2, 'a'), 
    (0, 1, 2, 'b'), 
    (0, 1, 2, 'c'), 
    (0, 1, 2, 'a'), 
    (3, 4, 5, 'x'), 
    (3, 4, 5, 'y'), 
    (3, 4, 5, 'x'), 
    (3, 4, 5, 'z'); 

Giải pháp:

select * from tbl; 

with a as 
(
    select row_number() over(partition by col1 order by col2, col3, colX) as rn 
    from tbl 
) 
delete from a where rn > 1; 

select * from tbl; 

outpu t:

| COL1 | COL2 | COL3 | COLX | 
----------------------------- 
| 0 | 1 | 2 | a | 
| 0 | 1 | 2 | b | 
| 0 | 1 | 2 | c | 
| 0 | 1 | 2 | a | 
| 3 | 4 | 5 | x | 
| 3 | 4 | 5 | y | 
| 3 | 4 | 5 | x | 
| 3 | 4 | 5 | z | 


| COL1 | COL2 | COL3 | COLX | 
----------------------------- 
| 0 | 1 | 2 | a | 
| 3 | 4 | 5 | x | 

Hoặc có lẽ đây: http://www.sqlfiddle.com/#!3/af826/1

dữ liệu:

CREATE TABLE tbl 
    ([col1] int, [col2] int, [col3] int, [colX] varchar(1)); 

INSERT INTO tbl 
    ([col1], [col2], [col3], [colX]) 
VALUES 
    (0, 1, 2, 'a'), 
    (0, 1, 2, 'b'), 
    (0, 1, 2, 'c'), 
    (0, 1, 2, 'a'), 
    (0, 1, 3, 'a'), 
    (3, 4, 5, 'x'), 
    (3, 4, 5, 'y'), 
    (3, 4, 5, 'x'), 
    (3, 4, 5, 'z'); 

Giải pháp:

select * from tbl; 


with a as 
(
    select row_number() over(partition by col1, col2, col3 order by colX) as rn 
    from tbl 
) 
delete from a where rn > 1; 

select * from tbl; 

Output:

| COL1 | COL2 | COL3 | COLX | 
----------------------------- 
| 0 | 1 | 2 | a | 
| 0 | 1 | 2 | b | 
| 0 | 1 | 2 | c | 
| 0 | 1 | 2 | a | 
| 0 | 1 | 3 | a | 
| 3 | 4 | 5 | x | 
| 3 | 4 | 5 | y | 
| 3 | 4 | 5 | x | 
| 3 | 4 | 5 | z | 

| COL1 | COL2 | COL3 | COLX | 
----------------------------- 
| 0 | 1 | 2 | a | 
| 0 | 1 | 3 | a | 
| 3 | 4 | 5 | x | 
+0

điều này đã làm cho nó, cảm ơn bạn rất nhiều –

2

Tôi sẽ đề nghị sử dụng CTE và đọc tất cả các bản ghi không song công trong một bảng riêng nếu bạn có nhiều bản sao. Tuy nhiên, có một bài khuyến khích để làm theo: MSDN

+1

Dường như bạn lần đầu tiên đề cập đến cách tiếp cận "CTE" sql, đây là cách đơn giản nhất và trong hầu hết các trường hợp nó hoạt động. –

1

Giả sử colX là duy nhất (mà không phải là trường hợp trong ví dụ của bạn, ngay cả khi bạn nói "khác nhau colX"), bạn có thể sử dụng sau đây để xóa các bản sao:

;with cteDuplicates as 
(
    select 
     *, 
     row_number() over (partition by col1, col2, col3 order by colX) as ID 
    from Duplicates 
) 
delete D from Duplicates D 
    inner join cteDuplicates C on C.colX = D.Colx 
where ID > 1 

(Hãy nói rằng bảng của bạn được đặt tên là "Bản sao")

Nếu colX không phải là độc đáo, thêm một cột uniqueidentifier mới, chèn giá trị khác biệt vào nó và sau đó sử dụng đoạn mã trên bằng cách tham gia vào cột đó thay vì colX.

2

Nếu bạn là OK với chỉ giữ giá trị tối thiểu của colX, bạn có thể làm điều này:

delete t from t inner join 
    (select min(colx) mincolx, col1, col2, col3 
    from t 
    group by col1, col2, col3 
    having count(1) > 1) as duplicates 
    on (duplicates.col1 = t.col1 
    and duplicates.col2 = t.col2 
    and duplicates.col3 = t.col3 
    and duplicates.mincolx <> t.colx) 

Vấn đề là bạn vẫn có hàng nơi mà tất cả bốn cột đều giống nhau. Để loại bỏ chúng, sau khi chạy truy vấn đầu tiên, bạn phải sử dụng bảng tạm thời.

SELECT distinct col1, col2, col3, colx 
INTO temp 
    FROM (SELECT col1, col2, col3 
     from t 
     group by col1, col2, col3 
     having count(1) > 1) subq; 

DELETE from t where exists 
    (select 1 from temp 
    where temp.col1 = t.col1 
     and temp.col2 = t.col2 
     and temp.col3 = t.col3); 

Here's an example SQLFiddle.

0

Tôi giả sử bạn đang sử dụng SQL Server 2005/2008.

SELECT col1, 
     col2, 
     col3, 
     colx 
FROM 
    (SELECT *, 
      row_number() OVER (PARTITION BY col1,col2,col3 
          ORDER BY colx) AS r 
    FROM table_name) a 
WHERE r = 1; 
0

giải pháp đơn giản nhất có thể là như sau giả sử chúng ta có bảng emp_dept (empid, deptID) trong đó có hàng trùng lặp, Mở cơ sở dữ liệu Oracle

delete from emp_dept where exists (select * from emp_dept i where i.empid = emp_dept.empid and i.deptid = emp_dept.deptid and i.rowid < emp_dept.rowid) 

Trên máy chủ sql hoặc anydatabase không hỗ trợ tính năng hàng id kinda, chúng tôi cần thêm cột nhận dạng chỉ để xác định mỗi hàng. nói, chúng tôi đã thêm vào nid như danh tính vào bảng

alter table emp_dept add nid int identity(1,1) -- to add identity column 

tại truy vấn để xóa trùng lặp có thể được viết như

delete from emp_dept where exists (select * from emp_dept i where i.empid = emp_dept.empid and i.deptid = emp_dept.deptid and i.nid< emp_dept.nid) 

Ở đây khái niệm này là xóa tất cả các hàng mà tồn tại hàng khác có tương tự giá trị cốt lõi nhưng nhỏ hơn rowid hoặc bản sắc. Do đó nếu có hàng trùng lặp thì một hàng có id hàng cao hơn hoặc nhận dạng sẽ bị xóa. và đối với hàng không có trùng lặp nó không tìm thấy id hàng thấp hơn do đó sẽ không bị xóa.

0

thử đoạn code BT này về nguy cơ của riêng bạn

Delete from Table_name 
WHERE Table_name.%%physloc%% 
     NOT IN (SELECT MAX(b.%%physloc%%) 
       FROM Table_name b 
       group by Col_1,Col_2) 

phương pháp thứ hai sử dụng row_number() đây là phương pháp an toàn

WITH CTE_Dup AS 
(

SELECT * ROW_NUMBER()OVER (PARTITIONBY SalesOrderno, ItemNo ORDER BY SalesOrderno, ItemNo) 
AS ROW_NO 
from dbo.SalesOrderDetails 
) 
Delete FROM CTE_Dup; 
Các vấn đề liên quan