Как выбрать самые нижние строки?
Я могу сделать выбор TOP (200) ... но почему не снизу (200)?
ну, чтобы не попасть в философию, что я имею в виду, как я могу сделать эквивалент TOP (200), но наоборот (снизу, как вы ожидали бы снизу...)?
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 )
В настоящее время принятый ответ "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, на самом деле не знает, что они просят. Или, по крайней мере, то, что они просят и то, что на самом деле означает дно, - это не одно и то же.
Так-решение может удовлетворить бизнес-потребности заказчика...но не соответствует критериям быть внизу.
попробуйте это.
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