Xóa tất cả trừ n trên cùng khỏi bảng cơ sở dữ liệu trong SQL


85

Cách tốt nhất để xóa tất cả các hàng khỏi bảng trong sql nhưng vẫn giữ n số hàng trên cùng là gì?

Câu trả lời:


80
DELETE FROM Table WHERE ID NOT IN (SELECT TOP 10 ID FROM Table)

Biên tập:

Chris mang lại hiệu suất tốt vì truy vấn TOP 10 sẽ được chạy cho mỗi hàng. Nếu đây là chuyện chỉ xảy ra một lần, thì nó có thể không phải là vấn đề lớn, nhưng nếu nó là một điều phổ biến, thì tôi đã xem xét kỹ hơn về nó.


4
Nếu ai đó thường cần xóa tất cả trừ n hàng trên cùng, tôi cho rằng họ có những vấn đề lớn hơn phải lo lắng.
Daniel Schaffer

6
Chỉ cần lưu ý rằng bạn có thể giải quyết vấn đề hiệu suất truy vấn con bằng cách tạo bảng tạm thời theo cách thủ công (giả sử đây là một hoạt động không thường xuyên) hoặc viết truy vấn DELETE FROM Table WHERE ID NOT IN (SELECT id FROM (SELECT TOP 10 ID FROM Table) AS x)để buộc MySQL tạo một bảng tạm thời.
Michael Mior

Cảm ơn bạn. Đó là một cứu cánh :)
Si8

1
Truy vấn con chạy nhiều lần, có đúng không? stackoverflow.com/questions/18790796/…
djluis

5
@ Daniel Schaffer Có vẻ như họ không gặp bất kỳ vấn đề db hoặc logic kinh doanh nào. Nghe có vẻ giống như một chính sách lưu giữ hoàn toàn bình thường.
Hejazzman

33

Tôi sẽ chọn (các) cột ID tập hợp các hàng mà bạn muốn giữ vào bảng tạm thời hoặc biến bảng. Sau đó, xóa tất cả các hàng không tồn tại trong bảng tạm thời. Cú pháp được đề cập bởi một người dùng khác:

DELETE FROM Table WHERE ID NOT IN (SELECT TOP 10 ID FROM Table)

Có một vấn đề tiềm ẩn. Truy vấn "CHỌN HÀNG ĐẦU 10" sẽ được thực thi cho mỗi hàng trong bảng, đây có thể là một lần truy cập hiệu suất rất lớn. Bạn muốn tránh lặp đi lặp lại cùng một truy vấn.

Cú pháp này sẽ hoạt động, dựa trên những gì bạn đã liệt kê dưới dạng câu lệnh SQL ban đầu của mình:

create table #nuke(NukeID int)

insert into #nuke(Nuke) select top 1000 id from article

delete article where not exists (select 1 from nuke where Nukeid = id)

drop table #nuke

3
insert into #nuke(Nuke) ...có lẽ nên là: insert into #nuke(NukeID) ...Ngoài ra, tên nuke gây nhầm lẫn vì bạn đang cố KHÔNG xóa các hàng này. nuke có lẽ được đặt tên theo thực tế là nó sẽ bị xóa.
Erno

12

Tài liệu tham khảo trong tương lai cho những người sử dụng không sử dụng MS SQL.

Trong PostgreSQL sử dụng ORDER BYLIMITthay vì TOP.

DELETE FROM table
WHERE id NOT IN (SELECT id FROM table ORDER BY id LIMIT n);

MySQL - tốt ...

Lỗi - Phiên bản MySQL này chưa hỗ trợ 'LIMIT & IN / ALL / ANY / SOME subquery'

Tôi đoán là chưa.


5

Tôi nghĩ rằng sử dụng một bảng ảo sẽ tốt hơn nhiều so với một mệnh đề IN hoặc bảng tạm thời.

DELETE 
    Product
FROM
    Product
    LEFT OUTER JOIN
    (
        SELECT TOP 10
            Product.id
        FROM
            Product
    ) TopProducts ON Product.id = TopProducts.id
WHERE
    TopProducts.id IS NULL

2

Tôi không biết về các hương vị khác nhưng MySQL DELETE cho phép LIMIT.

Nếu bạn có thể sắp xếp mọi thứ sao cho n hàng bạn muốn giữ ở dưới cùng, thì bạn có thể thực hiện XÓA khỏi bảng LIMIT số lượng bảng-n.

Biên tập

Ồ! Tôi nghĩ rằng tôi thích câu trả lời của Cory Foy hơn, giả sử nó hoạt động trong trường hợp của bạn. Cách của tôi cảm thấy hơi rắc rối khi so sánh.


2

Đây thực sự là ngôn ngữ cụ thể, nhưng tôi có thể sẽ sử dụng một cái gì đó như sau cho máy chủ SQL.

declare @n int
SET @n = SELECT Count(*) FROM dTABLE;
DELETE TOP (@n - 10 ) FROM dTable

nếu bạn không quan tâm đến số lượng hàng chính xác, luôn có

DELETE TOP 90 PERCENT FROM dTABLE;

1
Cả hai đều không hoạt động. Câu hỏi hỏi làm thế nào để chỉ giữ N hàng trên cùng trong một bảng. Cả hai ví dụ này chỉ giữ N hàng dưới cùng.
Chris

1
Hoạt động tốt trong MSSQL. Chỉ cần thêm một sắp xếp để xóa dưới cùng thay vì trên cùng?
MeanGreen

2

Đây là cách tôi đã làm điều đó. Phương pháp này nhanh hơn và đơn giản hơn:

Xóa tất cả trừ n đầu khỏi bảng cơ sở dữ liệu trong MS SQL bằng lệnh OFFSET

WITH CTE AS
    (
    SELECT  ID
    FROM    dbo.TableName
    ORDER BY ID DESC
    OFFSET 11 ROWS
    )
DELETE CTE;

Thay thế IDbằng cột mà bạn muốn sắp xếp. Thay thế số sau OFFSETbằng số hàng mà bạn muốn xóa. Chọn DESChoặc ASC- bất cứ điều gì phù hợp với trường hợp của bạn.


Phần bù sẽ không phải là số hàng bạn muốn giữ trong trường hợp này?
NapkinBob

@NapkinBob Có.
Harvey

0

Tôi sẽ giải quyết nó bằng cách sử dụng kỹ thuật dưới đây. Ví dụ mong đợi một bảng bài viết với một id trên mỗi hàng.

Delete article where id not in (select top 1000 id from article)

Chỉnh sửa: Quá chậm để trả lời câu hỏi của riêng tôi ...


0

Đã tái cấu trúc?

Delete a From Table a Inner Join (
    Select Top (Select Count(tableID) From Table) - 10) 
        From Table Order By tableID Desc
) b On b.tableID = A.tableID

chỉnh sửa: đã thử cả hai trong trình phân tích truy vấn, câu trả lời hiện tại được nhanh chóng (thứ tự chết tiệt bởi ...)


0

Cách tốt hơn là chèn các hàng bạn muốn vào một bảng khác, thả bảng gốc và sau đó đổi tên bảng mới để nó có cùng tên với bảng cũ


Tại sao điều đó tốt hơn? Nhanh hơn? Yêu cầu một vài lệnh bổ sung để hoàn thành.
MeanGreen

0

Tôi có một mẹo để tránh thực thi TOPbiểu thức cho mọi hàng. Chúng tôi có thể kết hợp TOPvới MAXđể có được những thứ MaxIdchúng tôi muốn giữ. Sau đó, chúng tôi chỉ cần xóa mọi thứ lớn hơn MaxId.

-- Declare Variable to hold the highest id we want to keep. 
DECLARE @MaxId as int = (
SELECT MAX(temp.ID)
FROM (SELECT TOP 10 ID FROM table ORDER BY ID ASC) temp
)

-- Delete anything greater than MaxId. If MaxId is null, there is nothing to delete.
IF @MaxId IS NOT NULL
    DELETE FROM table WHERE ID > @MaxId

Lưu ý: Điều quan trọng là sử dụng ORDER BYkhi khai báo MaxIdđể đảm bảo kết quả phù hợp được truy vấn.

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.