Como excluir as 1000 linhas principais de uma tabela usando o Sql Server 2008?

108

Tenho uma tabela no SQL Server. Eu gostaria de excluir as 1000 linhas principais dele. No entanto, tentei fazer isso, mas em vez de apenas excluir as 1000 linhas principais, excluí todas as linhas da tabela.

Aqui está o código:

delete from [mytab] 
select top 1000 
a1,a2,a3
from [mytab]
Edgarmtze
fonte
8
Você precisa de um ORDER BY para tornar TOP significativo: veja a resposta de @Martin Smith, que é a única de cinco a ter isso. Eu me desespero às vezes
gbn
2
Você deseja excluir quaisquer 1000 linhas? Selecionado apenas aleatoriamente? Ou, por exemplo, as 1000 linhas mais antigas principais?
Nick Chammas
13
Você excluiu toda a tabela porque delete from [mytab]é uma instrução e select top ...é outra.
Nick Chammas
2
Você não precisa pedir para o topo, depende de porque você está fazendo o TOP. Se você precisar remover 10 milhões de linhas e tiver 1 GB de espaço de log disponível, use Delete TOP (10000) From dbo.myTable (com sua cláusula select) e continue executando-o até que não haja mais linhas para excluir. Quem se importa se é arbitrário. A classificação apenas retarda a consulta.
tvanharp
1
Sei que essa é uma questão antiga (em tantos anos), mas acho que é importante que as pessoas considerem os comentários de @gbn . Embora seus comentários não se apliquem à minha situação (tentar excluir blocos de registros sem causar problemas de LOCK, mas não se importar realmente com a ordem em que são excluídos), eles podem muito provavelmente se aplicar à SUA situação. Certifique-se de considerá-los antes de utilizar cegamente as respostas abaixo que não incluem uma cláusula ORDER BY.
Andrew Steitz

Respostas:

195

O código que você tentou é, na verdade, duas instruções. A DELETEseguido por a SELECT.

Você não define TOPcomo ordenado por quê.

Para um critério de pedido específico, a exclusão de uma CTE ou expressão de tabela semelhante é a maneira mais eficiente.

;WITH CTE AS
(
SELECT TOP 1000 *
FROM [mytab]
ORDER BY a1
)
DELETE FROM CTE
Martin Smith
fonte
13
Para aqueles que estão se perguntando por que você não pode fazer isso DELETE TOP (1000) FROM table ORDER BY column, leia isto : "As linhas referenciadas na expressão TOP usada com INSERT, UPDATE, MERGE ou DELETE não estão organizadas em nenhuma ordem."
Nick Chammas
3
@Magnus sim. Mas não em 2000. Pode ser possível usar uma tabela derivada em 2000. Não tenho uma instância para testar.
Martin Smith
2
Eu tinha feito uma maneira um pouco diferente (embora eu ache que o CTE pode ser mais agradável de se olhar): DELETE T1 FROM (SELECT TOP 1000 * FROM [MYTAB] ORDER BY A1) T1;
Abacus
4
@Liam - só porque, se houver qualquer declaração anterior antes do CTE, ela precisa ser encerrada com um ponto-e-vírgula, portanto, anexá-lo à frente das WITHreclamações evita reclamações de pessoas que não fizeram isso.
Martin Smith
86

Pode ser melhor para sql2005 + usar:

DELETE TOP (1000)
FROM [MyTab]
WHERE YourConditions

Para Sql2000:

DELETE FROM [MyTab]
WHERE YourIdField IN 
(
  SELECT TOP 1000 
    YourIdField 
  FROM [MyTab]
  WHERE YourConditions
)

MAS

Se quiser excluir um subconjunto específico de linhas em vez de um subconjunto arbitrário, você deve especificar explicitamente a ordem da subconsulta:

DELETE FROM [MyTab]
WHERE YourIdField IN 
(
  SELECT TOP 1000 
    YourIdField 
  FROM [MyTab]
  WHERE YourConditions
  ORDER BY ExplicitSortOrder
)

Obrigado a tp @gbn por mencionar e exigir uma resposta mais clara e exata.

Oleg Dok
fonte
3
@gbn Talvez seja inútil para você, mas é exatamente isso que a pergunta está pedindo.
Joachim Isaksson
1
@Joachim Isaksson: vá e leia sobre o TOP e depois volte. Não existe TOP sem um ORDER BY em conjuntos. Como alternativa, encontre uma referência canônica que prove que estou errado ... Para evitar que você pesquise, sqlblog.com/blogs/alexander_kuznetsov/archive/2009/05/20/… e blogs.technet.com/b/wardpond/archive /
2007/07/19
1
@gbn Nenhuma condição sobre QUAIS linhas serão excluídas, então ORDER BY na subconsulta é inútil
Oleg Dok
1
@gbn Você mencionou WHERE na subconsulta - eu filtro 1000 linhas arbitrárias dentro dos critérios escolhidos e excluo então. Cenário válido? Sim. Se eu adicionar ORDER BY NEWID () ou qualquer outra coisa, nada muda - eu ainda excluo 1000 linhas filtradas pelos critérios escolhidos
Oleg Dok
8
@gbn Caso você esteja procurando um uso válido de TOP sem ORDER BY: o que me trouxe aqui é que preciso excluir todas as linhas que correspondem a alguns critérios, mas, por motivos de desempenho, não quero excluir mais de 10.000 linhas de uma vez. Não me importa quais linhas ele exclui, já que irei executar o comando novamente em algum intervalo até que todas essas linhas tenham desaparecido.
Richiban
6
delete from [mytab]
where [mytab].primarykeyid in
(
select top 1000 primarykeyid
from [mytab]
)
Jason Dam
fonte
4
Inútil: TOP sem ORDER BY fornece linhas arbitrárias
gbn
4
@gbn Talvez seja inútil para você, mas é exatamente isso que a pergunta está pedindo.
Joachim Isaksson
3
@gbn Eu não afirmei que haja uma ordem de classificação padrão ou que a consulta seja de alguma forma útil, apenas lembrei você de que a pergunta não era solicitada, então o que você sugere?
Joachim Isaksson
2
@gbn Não sei por que você é tão hostil com todo mundo sobre algo que é um ponto de partida. Não afirmo que minha resposta seja o fim de tudo, é apenas uma sugestão para ajudar alguém. Acho que a importância são as chaves que estão voltando da sub-consulta aqui.
Jason Dam
2
Isso pode ser tudo o que o solicitante está procurando. Gostaria apenas de acrescentar uma observação para outros leitores, para enfatizar que as linhas excluídas por tal instrução não têm garantia de estar em qualquer ordem.
Nick Chammas
3
SET ROWCOUNT 1000;

DELETE FROM [MyTable] WHERE .....
Joe Bourne
fonte
2
Ao lidar com apenas 1000 linhas, isso realmente importa ?? Se fosse 100.000.000 de linhas, seus pontos poderiam ser válidos, mas para apenas 1000 linhas, esta é de longe a solução mais simples proposta até agora para o SQL 2008.
Joe Bourne
1

Isso é rápido. Tente:

DELETE FROM YourTABLE
FROM (SELECT TOP XX PK FROM YourTABLE) tbl
WHERE YourTABLE.PK = tbl.PK

Substituir YourTABLEpelo nome da tabela, XXpor um número, por exemplo 1000, pké o nome do campo da chave primária da sua tabela.

Hamed elahi
fonte
Você está efetivamente criando duas tabelas a partir de uma e, em seguida, excluindo as unidas. Funciona bem quando você deseja excluir os registros mais antigos (ou mais recentes) de uma tabela, já que você pode classificá-los em ordem crescente primeiro. Este t-sql é aceito pela Microsoft (e é rápido).
Tequila