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;
BOTTOM (x) is all the records except TOP (n - x), where n is the count; x <= n
例如,从员工中选择垫底的1000名:
In 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
)
The currently accepted answer by "Justin Ethier" is not a correct answer as pointed out by "Protector one".
据我所知,到目前为止,还没有其他答案或评论提供与作者所要求的 BOTTOM (x)相当的答案。
首先,让我们考虑一个需要此功能的场景:
SELECT * FROM Split('apple,orange,banana,apple,lime',',')
This returns a table of one column and five records:
苹果
橙色
香蕉
苹果
酸橙
As you can see: we don't have an ID column; we can't order by the returned column; and we can't select the bottom two records using standard SQL like we can do for the top two records.
以下是我试图提供的解决方案:
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
And here is a more complete solution:
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
I am by no means claiming that this is a good idea to use in all circumstances, but it provides the desired results.
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
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 [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
It would seem that any of the answers which implement an ORDER BY clause in the solution is missing the point, or does not actually understand what TOP returns to you.
TOP 返回一个无序查询结果集,该结果集将记录集限制为返回的前 N 条记录。(从 Oracle 的角度来看,这类似于添加一个 where ROWNUM < (N + 1)。
任何使用顺序的解决方案,梅返回的行也由 TOP 子句返回(因为该数据集首先是无序的) ,这取决于 TOP 子句在顺序中使用了哪些条件
TOP 的有用之处在于,一旦数据集达到某个大小 N,它就停止获取行。您可以了解数据的外观,而无需获取所有数据。
为了准确地实现 BOTTOM,需要无序地获取整个数据集,然后将数据集限制为最终的 N 条记录。如果处理的桌子很大,这种方法就不会特别有效。它也不一定会给你什么你 好好想想你要求。数据集的末尾可能不一定是“插入的最后一行”(对于大多数 DML 密集型应用程序来说也可能不是)。
当记录被一遍又一遍地插入、删除、插入、删除时,存储器中会出现一些空白,以后,如果可能的话,行将被插入。但是我们经常看到,当我们选择 TOP 时,出现了将被排序数据,因为它可能在表存在的早期就已经插入。如果表没有经历许多删除,它可能 出现被排序。(例如,创建日期可能与表创建本身的时间一样久远)。但实际情况是,如果这是一个删除量很大的表,那么 TOP N 行可能根本不是这样的。
So -- the bottom line here(pun intended) is that someone who is asking for the BOTTOM N records doesn't actually know what they're asking for. Or, at least, what they're asking for and what BOTTOM actually means are not the same thing.
First, create an index in a subquery according to the table's original order using:
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
SELECT COUNT(1) FROM COHORT; --Number of results to expect
SELECT * FROM COHORT
ORDER BY ID
OFFSET 900 ROWS --Assuming you expect 1000 rows
FETCH NEXT 100 ROWS ONLY;