Elimina tutto tranne i primi n dalla tabella del database in SQL


86

Qual è il modo migliore per eliminare tutte le righe da una tabella in sql ma per mantenere il numero n di righe in alto?

Risposte:


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

Modificare:

Chris segnala un buon rendimento in quanto la query TOP 10 verrà eseguita per ogni riga. Se questa è una cosa una tantum, potrebbe non essere un grosso problema, ma se è una cosa comune, l'ho esaminata più da vicino.


6
Solo una nota che puoi risolvere il problema delle prestazioni delle sottoquery creando manualmente una tabella temporanea (supponendo che questa sia un'operazione rara) o scrivendo la query DELETE FROM Table WHERE ID NOT IN (SELECT id FROM (SELECT TOP 10 ID FROM Table) AS x)per forzare MySQL a creare una tabella temporanea.
Michael Mior

Grazie. È stato un
salvavita

1
La sottoquery viene eseguita più volte, è vero? stackoverflow.com/questions/18790796/...
djluis

5
@ Daniel Schaffer Non sembra che abbiano problemi di database o di logica aziendale. Sembra una politica di conservazione del tutto normale.
Hejazzman

33

Selezionare le colonne ID l'insieme di righe che si desidera mantenere in una tabella temporanea o in una variabile di tabella. Quindi elimina tutte le righe che non esistono nella tabella temporanea. La sintassi menzionata da un altro utente:

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

Ha un potenziale problema. La query "SELECT TOP 10" verrà eseguita per ogni riga della tabella, il che potrebbe essere un enorme calo delle prestazioni. Vuoi evitare di ripetere la stessa query più e più volte.

Questa sintassi dovrebbe funzionare, in base a ciò che hai elencato come istruzione SQL originale:

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) ...probabilmente dovrebbe essere: insert into #nuke(NukeID) ...Anche il nome nuke è fonte di confusione perché stai cercando di NON eliminare queste righe. nuke prende probabilmente il nome dal fatto che verrà cancellato.
Erno

12

Riferimento futuro per coloro che non utilizzano MS SQL.

In PostgreSQL usa ORDER BYe LIMITinvece di TOP.

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

MySQL - beh ...

Errore : questa versione di MySQL non supporta ancora "LIMIT & IN / ALL / ANY / SOME subquery"

Non ancora, credo.


5

Penso che l'utilizzo di una tabella virtuale sarebbe molto meglio di una clausola IN o di una tabella temporanea.

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

Non conosco altri sapori ma MySQL DELETE consente LIMIT.

Se potessi ordinare le cose in modo che le n righe che vuoi mantenere siano in fondo, allora potresti fare un DELETE FROM table LIMIT tablecount-n.

modificare

Oooo. Penso che la risposta di Cory Foy mi piaccia di più, ammesso che funzioni nel tuo caso. La mia strada sembra un po 'goffa al confronto.


2

Questo sarà davvero specifico della lingua, ma probabilmente userò qualcosa di simile al seguente per SQL Server.

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

se non ti interessa il numero esatto di righe, c'è sempre

DELETE TOP 90 PERCENT FROM dTABLE;

1
Nessuno di questi lavori. La domanda chiede come mantenere solo le prime N righe in una tabella. Entrambi questi esempi mantengono solo le ultime N righe.
Chris

1
Funziona bene in MSSQL. Basta aggiungere un ordinamento per eliminare la parte inferiore anziché la parte superiore?
MeanGreen

2

Ecco come l'ho fatto. Questo metodo è più veloce e più semplice:

Elimina tutto tranne i primi n dalla tabella del database in MS SQL utilizzando il comando OFFSET

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

Sostituisci IDcon la colonna in base alla quale desideri ordinare. Sostituisci il numero dopo OFFSETcon il numero di righe che desideri mantenere. Scegli DESCo ASC- qualunque cosa si adatti al tuo caso.


In questo caso, l'offset non sarebbe il numero di righe che desideri mantenere?
NapkinBob

@NapkinBob Sì.
Harvey

0

Lo risolverei usando la tecnica qui sotto. L'esempio prevede una tabella di articoli con un id su ogni riga.

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

Modifica: troppo lento per rispondere alla mia domanda ...


0

Refactored?

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

modifica: provali entrambi nell'analizzatore di query, la risposta corrente è a digiuno (dannazione per ...)


0

Il modo migliore sarebbe inserire le righe che vuoi in un'altra tabella, rilasciare la tabella originale e quindi rinominare la nuova tabella in modo che abbia lo stesso nome della vecchia tabella


Perché è meglio? Più veloce? Richiede un paio di comandi extra da eseguire.
MeanGreen

0

Ho un trucco per evitare di eseguire l' TOPespressione per ogni riga. Possiamo combinare TOPcon MAXper ottenere la MaxIdvogliamo mantenere. Quindi cancelliamo semplicemente tutto ciò che è maggiore di 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

Nota: è importante utilizzare ORDER BYdurante la dichiarazione MaxIdper garantire che vengano richiesti risultati corretti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.