Видаліть усі, крім верхніх n, з таблиці бази даних у SQL


85

Який найкращий спосіб видалити всі рядки з таблиці в sql, але зберегти n кількість рядків зверху?

Відповіді:


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

Редагувати:

Кріс показує хороший показник ефективності, оскільки запит ТОП 10 буде виконуватися для кожного рядка. Якщо це одноразова річ, то це може бути не така велика угода, але якщо це звичайна справа, то я все-таки придивився до цього.


4
Якщо комусь зазвичай потрібно видалити всі, крім верхніх n рядків, я б стверджував, що у них є більші проблеми, про які слід турбуватися.
Даніель Шаффер

6
Просто зауважте, що ви можете вирішити проблему продуктивності підзапиту, або створивши тимчасову таблицю вручну (припускаючи, що це нечаста операція), або написавши запит, DELETE FROM Table WHERE ID NOT IN (SELECT id FROM (SELECT TOP 10 ID FROM Table) AS x)щоб змусити MySQL створити тимчасову таблицю.
Michael Mior

Дякую. Це
врятувало

1
Підзапит запускається кілька разів, чи правда? stackoverflow.com/questions/18790796 / ...
djluis

5
@ Даніель Шаффер Не схоже, що у них є якісь проблеми з дб або бізнес-логікою. Це звучить як абсолютно нормальна політика утримання.
Геджазмен,

33

Я вибрав би стовпець (ідентифікатори) набору рядків, які ви хочете зберегти у тимчасовій таблиці або змінній таблиці. Потім видаліть усі рядки, які не існують у тимчасовій таблиці. Синтаксис, згаданий іншим користувачем:

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

Є потенційна проблема. Запит "ВИБЕРІТЬ ТОП 10" буде виконаний для кожного рядка таблиці, що може бути величезним показником продуктивності. Ви хочете уникати повторення одних і тих самих запитів.

Цей синтаксис повинен працювати, виходячи з того, що ви вказали як вихідний оператор SQL:

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) ...мабуть, має бути: insert into #nuke(NukeID) ...Також ім'я nuke заплутане, оскільки ви намагаєтесь НЕ видалити ці рядки. nuke, ймовірно, названий на честь того, що його буде видалено.
Ерно

12

Подальша довідка для тих, хто не використовує MS SQL.

У PostgreSQL використовують ORDER BYі LIMITзамість TOP.

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

MySQL - ну ...

Помилка - Ця версія MySQL ще не підтримує підзапит "LIMIT & IN / ALL / ANY / SOME"

Ще не здогадуюсь.


5

Я думаю, що використання віртуальної таблиці було б набагато кращим, ніж таблиця з пропозиціями IN або тимчасова таблиця.

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

Я не знаю про інші смаки, але MySQL DELETE дозволяє обмежити.

Якщо ви могли впорядкувати речі так, щоб n рядків, які ви хочете зберегти, знаходилися внизу, тоді ви могли б зробити ВИДАЛЕННЯ З таблиці LIMIT tablecount-n.

Редагувати

Оооо. Думаю , відповідь Кори Фоя мені більше подобається , якщо припустити, що це спрацьовує у вашому випадку. По-моєму, в порівнянні з цим я трохи незграбний.


2

Це дійсно буде мовно, але я б скоріш за все використав щось на зразок наступного для SQL-сервера.

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

якщо ви не дбаєте про точну кількість рядків, завжди є

DELETE TOP 90 PERCENT FROM dTABLE;

1
Нічого з цього не працює. Питання задає питання, як зберегти в таблиці лише верхні N рядків. Обидва ці приклади містять лише нижні N рядків.
Кріс

1
Чудово працює в MSSQL. Просто додайте сортування, щоб видалити нижній, а не верхній?
MeanGreen

2

Ось як я це зробив. Цей спосіб швидший і простіший:

Видаліть усі, крім верхніх n, з таблиці бази даних у MS SQL за допомогою команди OFFSET

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

Замініть IDна стовпець, за яким потрібно сортувати. Замініть число після OFFSETна кількість рядків, які потрібно видалити. Виберіть DESCабо ASC- все, що підходить для вашої справи.


Чи не буде зміщенням кількість рядків, які ви хочете зберегти в цьому випадку?
NapkinBob

@NapkinBob Так.
Харві

0

Я б вирішив це за допомогою наведеної нижче техніки. У прикладі очікується таблиця статей з ідентифікатором у кожному рядку.

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

Редагувати: занадто повільно відповідати на власне запитання ...


0

Перероблений?

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

редагувати: спробував їх обох в аналізаторі запитів, поточна відповідь голодується (проклятий порядок за ...)


0

Кращим способом було б вставити потрібні вам рядки в іншу таблицю, опустити вихідну таблицю, а потім перейменувати нову таблицю, щоб вона мала те саме ім'я, що і стара


Чому це краще? Швидше? Потрібна пара додаткових команд для виконання.
MeanGreen

0

У мене є хитрість, щоб уникнути виконання TOPвиразу для кожного рядка. Ми можемо поєднувати TOPз тим, MAXщоб отримати те, що MaxIdми хочемо зберегти. Тоді ми просто видаляємо все більше, ніж 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

Примітка: Важливо використовувати ORDER BYпри оголошенні, MaxIdщоб забезпечити відповідні запити.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.