Я могу выполнить SELECT TOP (200) ... но почему не BOTTOM (200)?
Ну, чтобы не вдаваться в философию, я имею в виду, как я могу сделать эквивалент TOP (200), но наоборот (снизу, как вы ожидаете, что BOTTOM сделает ...)?
Ответы:
SELECT
columns
FROM
(
SELECT TOP 200
columns
FROM
My_Table
ORDER BY
a_column DESC
) SQ
ORDER BY
a_column ASC
В этом нет необходимости. Вы можете использовать ORDER BY
и просто изменить сортировку, DESC
чтобы получить тот же эффект.
Извините, но я не думаю, что вижу правильные ответы, на мой взгляд.
Функция TOP
x показывает записи в неопределенном порядке. Из этого определения следует, что BOTTOM
функция не может быть определена.
Независимо от какого-либо индекса или порядка сортировки. Когда вы делаете это, ORDER BY y DESC
вы сначала получаете строки с наибольшим значением y. Если это автоматически сгенерированный идентификатор, он должен отображать записи, добавленные в таблицу последними, как это предлагается в других ответах. Тем не мение:
TOP
функциейПравильный ответ должен заключаться в том, что нет и не может быть эквивалента TOP
для получения нижних строк.
Логически,
BOTTOM (x) is all the records except TOP (n - x), where n is the count; x <= n
Например, выберите «Нижние 1000» из списка «Сотрудник»:
В 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
)
Казалось бы, в любом из ответов, реализующих предложение ORDER BY в решении, отсутствует суть или на самом деле не понимается, что возвращает вам TOP.
TOP возвращает неупорядоченный набор результатов запроса, который ограничивает набор записей первыми N возвращенными записями. (С точки зрения Oracle, это похоже на добавление where ROWNUM <(N + 1).
Любое решение, использующее порядок, может возвращать строки, которые также возвращаются предложением TOP (поскольку этот набор данных был изначально неупорядочен), в зависимости от того, какие критерии использовались в порядке
Полезность TOP заключается в том, что как только набор данных достигает определенного размера N, он прекращает выборку строк. Вы можете почувствовать, как выглядят данные, без необходимости извлекать их все.
Для точной реализации BOTTOM потребуется извлечь весь набор данных в неупорядоченном виде, а затем ограничить набор данных последними N записями. Это не будет особенно эффективно, если вы имеете дело с огромными таблицами. Это также не обязательно даст вам то, о чем вы думаете . Конец набора данных не обязательно может быть «последними вставленными строками» (и, вероятно, не будет для большинства приложений с интенсивным использованием DML).
Точно так же решения, реализующие ORDER BY, к сожалению, потенциально губительны при работе с большими наборами данных. Если у меня есть, скажем, 10 миллиардов записей и мне нужны последние 10, было бы глупо заказывать 10 миллиардов записей и выбирать последние 10.
Проблема здесь в том, что BOTTOM не имеет того значения, о котором мы думаем, сравнивая его с TOP.
Когда записи вставляются, удаляются, вставляются, удаляются снова и снова, в хранилище появляются пробелы, а позже строки будут вставлены, если это возможно. Но то, что мы часто видим, когда выбираем TOP, оказывается отсортированными данными, потому что они могли быть вставлены на ранней стадии существования таблицы. Если в таблице не много удалений, может показаться, что она упорядочена. (например, даты создания могут быть такими же далекими, как и само создание таблицы). Но на самом деле, если это таблица с большим количеством удалений, строки TOP N могут выглядеть совсем не так.
Итак - суть здесь (каламбур) заключается в том, что кто-то, кто запрашивает BOTTOM N записей, на самом деле не знает, что они просят. Или, по крайней мере, то, что они просят, и то, что на самом деле означает BOTTOM, - не одно и то же.
Итак - решение может удовлетворить фактические бизнес-потребности отправителя запроса ... но не соответствует критериям НИЖНЕГО.
insert
выполнил большой оператор, чтобы поместить строки в большую неиндексированную таблицу. (Я сначала заполняю таблицу, прежде чем начну ее индексировать.) Я потерял сеанс клиента из-за перезагрузки или чего-то еще, и теперь я хочу увидеть, есть ли там мои недавно добавленные строки. Если «нижняя» строка таблицы - одна из моих недавних, я знаю, что операция завершена. Если «нижняя» строка - это что-то еще, что ж, нет никаких гарантий, и я должен просканировать всю таблицу, чтобы убедиться ... но, скорее всего, я мог бы сэкономить время, быстро проверив «нижнюю», как вы можете верхняя'.
В настоящее время принятый ответ Джастина Этье не является правильным ответом, как указывает «Защитник один».
Насколько я понимаю, на данный момент ни один другой ответ или комментарий не дает эквивалента 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
Я ни в коем случае не утверждаю, что это хорошая идея для использования при любых обстоятельствах, но она дает желаемые результаты.
Все, что вам нужно сделать, это перевернуть ваш ORDER BY
. Добавить или удалить DESC
к нему.
Проблема с другим способом упорядочивания состоит в том, что при этом часто не используются индексы. Он также не очень расширяемый, если вам когда-либо понадобится выбрать количество строк, которые не находятся в начале или в конце. Альтернативный способ заключается в следующем.
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
Спасибо.
попробуй это.
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 TOP 10*from TABLE1 ORDER BY ID DESC
Где ID - это первичный ключ таблицы TABLE1.
Сначала создайте индекс в подзапросе в соответствии с исходным порядком таблицы, используя:
ROW_NUMBER () OVER (ORDER BY (SELECT NULL) ) AS RowIndex
Затем упорядочите таблицу по убыванию по RowIndex
столбцу, который вы создали в основном запросе:
ORDER BY RowIndex DESC
И, наконец, используйте TOP
желаемое количество строк:
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