Respostas:
SELECT
columns
FROM
(
SELECT TOP 200
columns
FROM
My_Table
ORDER BY
a_column DESC
) SQ
ORDER BY
a_column ASC
Isso é desnecessário. Você pode usar um ORDER BY
e apenas alterar o tipo para DESC
para obter o mesmo efeito.
Desculpe, mas acho que não vejo nenhuma resposta correta em minha opinião.
A TOP
função x mostra os registros em ordem indefinida. Dessa definição segue que uma BOTTOM
função não pode ser definida.
Independente de qualquer índice ou ordem de classificação. Quando você faz um, ORDER BY y DESC
obtém primeiro as linhas com o valor y mais alto. Se for um ID gerado automaticamente, deve mostrar os últimos registros adicionados à tabela, conforme sugerido nas demais respostas. Contudo:
TOP
funçãoA resposta correta deve ser que não há, e não pode haver, um equivalente TOP
para obter as linhas de baixo.
Logicamente,
BOTTOM (x) is all the records except TOP (n - x), where n is the count; x <= n
Por exemplo, selecione 1000 inferiores do funcionário:
Em T-SQL,
DECLARE
@bottom int,
@count int
SET @bottom = 1000
SET @count = (select COUNT(*) from Employee)
select * from Employee emp where emp.EmployeeID not in
(
SELECT TOP (@count-@bottom) Employee.EmployeeID FROM Employee
)
Parece que qualquer uma das respostas que implementam uma cláusula ORDER BY na solução está perdendo o ponto ou não entende o que TOP retorna para você.
TOP retorna um conjunto de resultados de consulta não ordenado que limita o conjunto de registros aos primeiros N registros retornados. (Da perspectiva do Oracle, é semelhante a adicionar um where ROWNUM <(N + 1).
Qualquer solução que usa um pedido, pode retornar linhas que também são retornadas pela cláusula TOP (desde que esse conjunto de dados foi desordenado em primeiro lugar), dependendo de quais critérios foram usados na ordem por
A utilidade do TOP é que uma vez que o conjunto de dados atinge um certo tamanho N, ele para de buscar linhas. Você pode ter uma ideia da aparência dos dados sem precisar buscá-los todos.
Para implementar o BOTTOM com precisão, seria necessário buscar todo o conjunto de dados não ordenado e, em seguida, restringir o conjunto de dados aos N registros finais. Isso não será particularmente eficaz se você estiver lidando com mesas enormes. Nem vai necessariamente dar o que você pensa que está pedindo. O final do conjunto de dados pode não ser necessariamente "as últimas linhas inseridas" (e provavelmente não será para a maioria dos aplicativos DML intensivos).
Da mesma forma, as soluções que implementam um ORDER BY são, infelizmente, potencialmente desastrosas ao lidar com grandes conjuntos de dados. Se eu tenho, digamos, 10 bilhões de registros e quero os últimos 10, é uma grande tolice solicitar 10 bilhões de registros e selecionar os últimos 10.
O problema aqui é que BOTTOM não tem o significado que pensamos ao compará-lo com TOP.
Quando os registros são inseridos, excluídos, inseridos, excluídos repetidamente, algumas lacunas aparecerão no armazenamento e, posteriormente, as linhas serão encaixadas, se possível. Mas o que vemos frequentemente, quando selecionamos TOP, parece ser dados classificados, porque podem ter sido inseridos no início da existência da tabela. Se a tabela não apresentar muitas exclusões, pode aparecer ordenada. (por exemplo, as datas de criação podem ser tão antigas quanto a própria criação da tabela). Mas a realidade é que, se esta for uma tabela com muitas exclusões, as linhas TOP N podem não se parecer com nada.
Então - o ponto principal aqui (trocadilho intencional) é que alguém que está pedindo os registros BOTTOM N não sabe realmente o que está pedindo. Ou, pelo menos, o que eles estão pedindo e o que BOTTOM realmente significa não são a mesma coisa.
Portanto - a solução pode atender à necessidade real de negócios do solicitante ... mas não atende aos critérios para ser o BOTTOM.
insert
declaração para colocar linhas em uma grande tabela não indexada. (Estou preenchendo a tabela antes de começar a indexá-la.) Perdi minha sessão de cliente devido a uma reinicialização ou algo assim, e agora quero ver se minhas linhas recém-adicionadas estão lá. Se a linha 'inferior' da tabela for uma das minhas mais recentes, sei que a operação foi concluída. Se a linha 'inferior' for outra coisa, bem, não há garantias e eu tenho que verificar toda a tabela para ter certeza ... mas provavelmente eu poderia economizar algum tempo verificando rapidamente a 'parte inferior' assim como você pode topo'.
A resposta atualmente aceita por "Justin Ethier" não é uma resposta correta como apontado por "Protetor um".
Até onde posso ver, até o momento, nenhuma outra resposta ou comentário fornece o equivalente a BOTTOM (x) que o autor da pergunta fez.
Primeiro, vamos considerar um cenário em que essa funcionalidade seja necessária:
SELECT * FROM Split('apple,orange,banana,apple,lime',',')
Isso retorna uma tabela de uma coluna e cinco registros:
Como você pode ver: não temos uma coluna de ID; não podemos ordenar pela coluna retornada; e não podemos selecionar os dois últimos registros usando o SQL padrão como podemos fazer para os dois primeiros registros.
Aqui está minha tentativa de fornecer uma solução:
SELECT * INTO #mytemptable FROM Split('apple,orange,banana,apple,lime',',')
ALTER TABLE #mytemptable ADD tempID INT IDENTITY
SELECT TOP 2 * FROM #mytemptable ORDER BY tempID DESC
DROP TABLE #mytemptable
E aqui está uma solução mais completa:
SELECT * INTO #mytemptable FROM Split('apple,orange,banana,apple,lime',',')
ALTER TABLE #mytemptable ADD tempID INT IDENTITY
DELETE FROM #mytemptable WHERE tempID <= ((SELECT COUNT(*) FROM #mytemptable) - 2)
ALTER TABLE #mytemptable DROP COLUMN tempID
SELECT * FROM #mytemptable
DROP TABLE #mytemptable
Não estou de forma alguma afirmando que esta é uma boa idéia para usar em todas as circunstâncias, mas fornece os resultados desejados.
Tudo que você precisa fazer é reverter seu ORDER BY
. Adicione ou remova DESC
-o.
O problema de ordenar de outra forma é que muitas vezes não faz bom uso dos índices. Também não é muito extensível se você precisar selecionar um número de linhas que não estão no início ou no final. Uma forma alternativa é a seguinte.
DECLARE @NumberOfRows int;
SET @NumberOfRows = (SELECT COUNT(*) FROM TheTable);
SELECT col1, col2,...
FROM (
SELECT col1, col2,..., ROW_NUMBER() OVER (ORDER BY col1) AS intRow
FROM TheTable
) AS T
WHERE intRow > @NumberOfRows - 20;
A resposta "Tom H" acima está correta e funciona para mim ao obter as 5 linhas inferiores.
SELECT [KeyCol1], [KeyCol2], [Col3]
FROM
(SELECT TOP 5 [KeyCol1],
[KeyCol2],
[Col3]
FROM [dbo].[table_name]
ORDER BY [KeyCol1],[KeyCol2] DESC) SOME_ALAIS
ORDER BY [KeyCol1],[KeyCol2] ASC
Obrigado.
tente isso.
declare @floor int --this is the offset from the bottom, the number of results to exclude
declare @resultLimit int --the number of results actually retrieved for use
declare @total int --just adds them up, the total number of results fetched initially
--following is for gathering top 60 results total, then getting rid of top 50. We only keep the last 10
set @floor = 50
set @resultLimit = 10
set @total = @floor + @resultLimit
declare @tmp0 table(
--table body
)
declare @tmp1 table(
--table body
)
--this line will drop the wanted results from whatever table we're selecting from
insert into @tmp0
select Top @total --what to select (the where, from, etc)
--using floor, insert the part we don't want into the second tmp table
insert into @tmp1
select top @floor * from @tmp0
--using select except, exclude top x results from the query
select * from @tmp0
except
select * from @tmp1
Eu encontrei uma solução para isso que não exige que você saiba o número de linhas retornadas.
Por exemplo, se você deseja obter todos os locais registrados em uma tabela, exceto o mais recente 1 (ou 2, ou 5 ou 34)
SELECT *
FROM
(SELECT ROW_NUMBER() OVER (ORDER BY CreatedDate) AS Row, *
FROM Locations
WHERE UserId = 12345) AS SubQuery
WHERE Row > 1 -- or 2, or 5, or 34
SELECT TOP 10*from TABLE1 ORDER BY ID DESC
Onde ID é a chave primária da TABELA1.
Primeiro, crie um índice em uma subconsulta de acordo com a ordem original da tabela usando:
ROW_NUMBER () OVER (ORDER BY (SELECT NULL) ) AS RowIndex
Em seguida, ordene a tabela em ordem decrescente pela RowIndex
coluna que você criou na consulta principal:
ORDER BY RowIndex DESC
E, finalmente, use TOP
com a quantidade desejada de linhas:
SELECT TOP 1 * --(or 2, or 5, or 34)
FROM (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL) ) AS RowIndex, *
FROM MyTable) AS SubQuery
ORDER BY RowIndex DESC