如何选择最底部的行?

我可以选择顶部(200) ... 但为什么不底部(200) ?

我不是说哲学,我的意思是,我怎样才能做到相当于 TOP (200) ,而是相反(从底部开始,就像你期望 BOTTOM 做的那样... ...) ?

357815 次浏览

这是不必要的。你可以使用一个 ORDER BY,只是改变排序为 DESC,以获得相同的效果。

所有你需要做的就是反转你的 ORDER BY。添加或删除 DESC到它。

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

另一种排序方式的问题在于,它常常不能很好地利用索引。如果您需要选择一些不在开始或结束位置的行,那么它也不是非常可扩展的。另一种方法如下。

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;

Sorry, but I don't think I see any correct answers in my opinion.

函数以未定义的顺序显示记录。根据这个定义,就不能定义 BOTTOM函数。

独立于任何索引或排序顺序。当执行 ORDER BY y DESC时,首先得到 y 值最高的行。如果这是一个自动生成的 ID,它应该显示最后添加到表中的记录,如其他答案所示。然而:

  • 这只有在有一个自动生成的 id 列时才有效
  • 如果将其与 TOP函数进行比较,则会对性能产生重大影响

正确的答案应该是,不存在、也不可能存在一个等价于 TOP的底部行。

逻辑上讲,

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

我想出了一个解决方案,它不需要您知道返回的行数。

例如,如果希望获取表中记录的所有位置,除了最新的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

“汤姆 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

谢谢。

按降序查询一个简单的子查询,然后对同一列进行升序排序。

SELECT * FROM
(SELECT TOP 200 * FROM [table] t2 ORDER BY t2.[column] DESC) t1
ORDER BY t1.[column]

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 密集型应用程序来说也可能不是)。

类似地,不幸的是,实现 ORDERBY 的解决方案在处理大型数据集时可能是灾难性的。如果我有,比如说,100亿条记录,想要最后的10条,那么订购100亿条记录并选择最后的10条记录是相当愚蠢的。

这里的问题是,在比较 TOP 时,BOTTOM 没有我们 想想的意义。

当记录被一遍又一遍地插入、删除、插入、删除时,存储器中会出现一些空白,以后,如果可能的话,行将被插入。但是我们经常看到,当我们选择 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.

因此——解决方案可能满足请求者的实际业务需求... ... 但不符合成为底层的标准。

SELECT TOP 10*from TABLE1 ORDER BY ID DESC

其中 ID 是 TABLE1的主键。

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

可以使用 offSETFETCH 子句。

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;

(这是给 Microsoft SQL Server 的)

官方文件: Https://www.sqlservertutorial.net/sql-server-basics/sql-server-offset-fetch/