Как выбрать самые нижние строки?


Я могу сделать выбор TOP (200) ... но почему не снизу (200)?

ну, чтобы не попасть в философию, что я имею в виду, как я могу сделать эквивалент TOP (200), но наоборот (снизу, как вы ожидали бы снизу...)?

13 83

13 ответов:

SELECT
    columns
FROM
(
     SELECT TOP 200
          columns
     FROM
          My_Table
     ORDER BY
          a_column DESC
) SQ
ORDER BY
     a_column ASC

это лишнее. Вы можете использовать ORDER BY и просто изменить вид DESC чтобы получить тот же эффект.

Извините, но я не думаю, что я вижу правильные ответы на мой взгляд.

The TOP функция x показывает записи в неопределенном порядке. Из этого определения следует, что BOTTOM функция не может быть определена.

независимо от любого индекса или порядка сортировки. Когда вы делаете ORDER BY y DESC сначала вы получаете строки с самым высоким значением Y. Если это автогенерированный идентификатор, он должен показывать записи, последние добавленные в таблицу, как это предлагается в других ответах. Однако:

  • это работает только в том случае, если есть автогенерированный столбец id
  • это имеет значительное влияние на производительность, если вы сравните это с TOP функции

правильный ответ должен заключаться в том, что нет и не может быть эквивалента TOP для получения нижних рядов.

выберите нижнюю 1000 от сотрудника

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
)

все, что вам нужно сделать, это изменить свое ORDER BY. Добавить или удалить DESC к нему.

В настоящее время принятый ответ "Justin Ethier" не является правильным ответом, как указано в "Protector one".

насколько я могу видеть, на данный момент ни один другой ответ или комментарий не дает эквивалента BOTTOM(x), который задал автор вопроса.

во-первых, давайте рассмотрим сценарий, где эта функциональность будет необходима:

SELECT * FROM Split('apple,orange,banana,apple,lime',',')

Это возвращает таблицу из одного столбца и пять рекорды:

  • яблоко
  • оранжевый
  • банан
  • яблоко
  • извести

как вы можете видеть: у нас нет столбца ID; мы не можем заказать по возвращенному столбцу; и мы не можем выбрать нижние две записи с помощью стандартного SQL, как мы можем сделать для двух верхних записей.

вот моя попытка предложить решение:

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

а вот и более полная решение:

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

Я ни в коем случае не утверждаю, что это хорошая идея для использования во всех обстоятельствах, но она обеспечивает желаемые результаты.

проблема с заказом другим способом заключается в том, что он часто не использует индексы. Он также не очень расширяется, если вам когда-либо понадобится выбрать несколько строк, которые не находятся в начале или конце. Альтернативный способ заключается в следующем.

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;

ответ "Tom H" выше правильный, и он работает для меня в получении нижних 5 строк.

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

спасибо.

казалось бы, что любой из ответов, которые реализуют предложение ORDER BY в решении, отсутствует точка или фактически не понимает, что TOP возвращает вам.

верхняя возвращает неупорядоченный запроса результирующий набор, который ограничивает набор записей, чтобы первые N записей, возвращаемых. (С точки зрения оракула, это сродни добавлению где ROWNUM

любое решение, которое использует ордера мая возвращаемые строки, которые также возвращаются предложением TOP (поскольку этот набор данных был неупорядочен в первую очередь), в зависимости от того, какие критерии использовались в порядке

полезность TOP заключается в том, что как только набор данных достигает определенного размера N, он перестает извлекать строки. Вы можете получить представление о том, как выглядят данные, не извлекая их все.

чтобы точно реализовать BOTTOM, ему нужно будет извлечь весь набор данных неупорядоченным, а затем ограничить набор данных до конечных записей N. Что не будет особо эффективным, если вы имеете дело с огромными таблицами. И это не обязательно даст вам то, что вы думаю вы просите. Конец набора данных может не обязательно быть "последними вставленными строками" (и, вероятно, не будет для большинства интенсивных приложений DML).

аналогичным образом, решения, которые реализуют ORDER BY, к сожалению, потенциально катастрофичны при работе с большими наборами данных. Если у меня есть, скажем, 10 миллиардов записей и я хочу последние 10, это довольно глупо заказывать 10 миллиардов записей и выберите последние 10.

проблема здесь в том, что дно не имеет того значения, что мы думать при сравнении его с верхней.

когда записи вставляются, удаляются, вставляются, удаляются снова и снова, некоторые пробелы появятся в хранилище, а затем строки будут прорезаны, если это возможно. Но то, что мы часто видим, когда выбираем TOP,появляется для сортировки данных, потому что он, возможно, был вставлен в начале существование стола. Если таблица не испытывает много удалений, это может появляется, котор нужно приказать. (например, даты создания могут быть такими же далекими во времени, как и само создание таблицы). Но реальность такова, что если это таблица с удалением, верхние n строк могут вообще не выглядеть так.

Итак, суть здесь (каламбур) заключается в том, что кто-то, кто просит нижние записи N, на самом деле не знает, что они просят. Или, по крайней мере, то, что они просят и то, что на самом деле означает дно, - это не одно и то же.

Так-решение может удовлетворить бизнес-потребности заказчика...но не соответствует критериям быть внизу.

SELECT TOP 10*from TABLE1 ORDER BY ID DESC

где ID-первичный ключ таблицы 1.

попробуйте это.

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

Я придумал решение, которое не требует, чтобы вы знали число строк, возвращаемых.

например, если вы хотите получить все местоположения, зарегистрированные в таблице, за исключением последнего 1 (или 2, или 5, или 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 * FROM 
    (SELECT TOP 200 * FROM [table] t2 ORDER BY t2.[column] DESC) t1
    ORDER BY t1.[column]