Usuń wszystkie n poza górnymi z tabeli bazy danych w języku SQL


85

Jaki jest najlepszy sposób usunięcia wszystkich wierszy z tabeli w sql, ale pozostawienie n liczby wierszy na górze?

Odpowiedzi:


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

Edytować:

Chris wskazuje na dobrą wydajność, ponieważ zapytanie TOP 10 zostanie uruchomione dla każdego wiersza. Jeśli jest to jednorazowa sprawa, może to nie być taka wielka sprawa, ale jeśli jest to powszechna rzecz, przyjrzałem się temu bliżej.


4
Jeśli ktoś zwykle musi usunąć wszystkie n wierszy oprócz górnych, twierdzę, że ma większe problemy, o które musi się martwić.
Daniel Schaffer,

6
Tylko uwaga, że ​​możesz rozwiązać problem z wydajnością podzapytania poprzez ręczne utworzenie tabeli tymczasowej (zakładając, że jest to rzadka operacja) lub napisanie zapytania, DELETE FROM Table WHERE ID NOT IN (SELECT id FROM (SELECT TOP 10 ID FROM Table) AS x)aby zmusić MySQL do utworzenia tabeli tymczasowej.
Michael Mior

Dziękuję Ci. To
uratowało

1
Podzapytanie jest uruchamiane wiele razy, czy to prawda? stackoverflow.com/questions/18790796/…
djluis

5
@ Daniel Schaffer Wygląda na to, że nie mają problemów z bazą danych lub logiką biznesową. Brzmi jak całkowicie normalna polityka przechowywania.
Hejazzman

33

Wybrałbym kolumny ID zestaw wierszy, które chcesz zachować w tabeli tymczasowej lub zmiennej tabeli. Następnie usuń wszystkie wiersze, które nie istnieją w tabeli tymczasowej. Składnia wspomniana przez innego użytkownika:

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

Ma potencjalny problem. Zapytanie „SELECT TOP 10” zostanie wykonane dla każdego wiersza w tabeli, co może mieć ogromny wpływ na wydajność. Chcesz uniknąć ciągłego wykonywania tego samego zapytania.

Ta składnia powinna działać w oparciu o to, co podałeś jako oryginalną instrukcję 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) ...prawdopodobnie powinno być: insert into #nuke(NukeID) ...Również nazwa nuke jest myląca, ponieważ próbujesz NIE usunąć tych wierszy. nuke prawdopodobnie nosi nazwę po tym, że zostanie usunięty.
Erno,

12

Przyszłe odniesienie dla użytkowników, którzy nie używają MS SQL.

W PostgreSQL użyj ORDER BYi LIMITzamiast TOP.

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

MySQL - cóż ...

Błąd - ta wersja MySQL nie obsługuje jeszcze „LIMIT & IN / ALL / ANY / SOME subquery”

Chyba jeszcze nie.


5

Myślę, że użycie wirtualnej tabeli byłoby znacznie lepsze niż klauzula IN lub tabela tymczasowa.

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

Nie wiem o innych smakach, ale MySQL DELETE dopuszcza LIMIT.

Jeśli mógłbyś tak uporządkować rzeczy, aby n wierszy, które chcesz zachować, znajdowało się na dole, możesz wykonać polecenie DELETE FROM table LIMIT tablecount-n.

Edytować

Oooo. Myślę, że bardziej podoba mi się odpowiedź Cory Foy , zakładając, że zadziała w twoim przypadku. W porównaniu z tym mój sposób wydaje się trochę niezgrabny.


2

To naprawdę będzie specyficzne dla języka, ale prawdopodobnie użyłbym czegoś takiego jak poniżej dla serwera SQL.

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

jeśli nie zależy Ci na dokładnej liczbie wierszy, zawsze jest

DELETE TOP 90 PERCENT FROM dTABLE;

1
Żadne z tych nie działa. Pytanie dotyczy zachowania tylko N górnych wierszy w tabeli. Oba te przykłady zachowują tylko N dolnych rzędów.
Chris

1
Działa dobrze w MSSQL. Po prostu dodaj sortowanie, aby usunąć dół zamiast góry?
MeanGreen

2

Oto jak to zrobiłem. Ta metoda jest szybsza i prostsza:

Usuń wszystkie n poza górnymi z tabeli bazy danych w MS SQL za pomocą polecenia OFFSET

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

Zastąp IDkolumną, według której chcesz sortować. Zastąp liczbę po OFFSETliczbie wierszy, które chcesz usunąć. Wybierz DESClub ASC- cokolwiek pasuje do Twojego przypadku.


Czy przesunięcie nie byłoby liczbą wierszy, które chcesz zachować w tym przypadku?
NapkinBob

@NapkinBob Yes.
Harvey

0

Rozwiązałbym to za pomocą poniższej techniki. Przykład oczekuje tabeli artykułów z identyfikatorem w każdym wierszu.

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

Edycja: zbyt wolno, aby odpowiedzieć na moje własne pytanie ...


0

Refaktoryzowany?

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

edycja: wypróbowałem je oba w analizatorze zapytań, aktualna odpowiedź jest szybka (cholerna kolejność ...)


0

Lepszym sposobem byłoby wstawienie żądanych wierszy do innej tabeli, usunięcie oryginalnej tabeli, a następnie zmiana nazwy nowej tabeli, tak aby miała taką samą nazwę jak stara tabela


Dlaczego tak jest lepiej? Szybciej? Do wykonania wymaga kilku dodatkowych poleceń.
MeanGreen

0

Mam sztuczkę, aby uniknąć wykonywania TOPwyrażenia dla każdego wiersza. Możemy łączyć TOPsię, MAXaby uzyskać to, MaxIdco chcemy zachować. Następnie po prostu usuwamy wszystko większe niż 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

Uwaga: Ważne jest, aby używać go ORDER BYprzy deklarowaniu, MaxIdaby zapewnić prawidłowe wyniki.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.