sql - 如何选择最底行?

我可以做SELECT TOP(200)......但为什么BOTTOM(200)呢?

好吧,不要进入哲学我的意思是,我怎么能做相当于TOP(200)但相反(从底部开始,就像你期望BOTTOM做的那样......)?

MetaGuru asked 2019-09-09T12:00:06Z
14个解决方案
91 votes

这是不必要的。 您可以使用ORDER BY,只需将排序更改为DESC即可获得相同的效果。

Justin Ethier answered 2019-09-09T12:00:40Z
77 votes
SELECT
    columns
FROM
(
     SELECT TOP 200
          columns
     FROM
          My_Table
     ORDER BY
          a_column DESC
) SQ
ORDER BY
     a_column ASC
Tom H answered 2019-09-09T12:00:12Z
31 votes

对不起,但我认为我认为没有看到任何正确的答案。

TOP x函数以未定义的顺序显示记录。 从该定义可以看出,无法定义BOTTOM函数。

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

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

正确的答案应该是,没有,也不能,等于TOP获取底行。

Martijn Burger answered 2019-09-09T12:01:38Z
14 votes

从员工中选择Bottom 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
)
Shadi Namrouti answered 2019-09-09T12:02:05Z
3 votes

正如“保护者一”所指出的那样,“Justin Ethier”目前接受的答案并不是正确的答案。

据我所知,截至目前,没有其他答案或评论提供与作者要求的问题相同的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

我并不是说在所有情况下使用这个都是个好主意,但它提供了理想的结果。

tomosius answered 2019-09-09T12:04:00Z
2 votes

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

Justin Swartsel answered 2019-09-09T12:04:26Z
1 votes

排序另一种方式的问题是它通常不能很好地利用索引。 如果您需要选择不在开头或结尾的行数,它也不是非常可扩展的。 另一种方法如下。

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;
Paul answered 2019-09-09T12:04:52Z
1 votes

上面的“汤姆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

谢谢。

user3598017 answered 2019-09-09T12:05:19Z
1 votes

似乎在解决方案中实现ORDER BY子句的任何答案都缺少这一点,或者实际上并不了解TOP返回给您的内容。

TOP返回无序查询结果集,该结果集将记录集限制为返回的前N个记录。 (从Oracle的角度来看,它类似于添加ROWNUM <(N + 1)。

任何使用订单的解决方案都可能返回也由TOP子句返回的行(因为该数据集首先是无序的),具体取决于订单中使用的标准

TOP的用处是,一旦数据集达到特定大小N,它就会停止获取行。 无需获取所有数据,您就可以了解数据的外观。

要准确地实现BOTTOM,需要获取无序的整个数据集,然后将数据集限制为最终的N个记录。 如果你正在处理庞大的表格,这将不会特别有效。 它也不一定会给你你认为你要求的东西。 数据集的末尾可能不一定是“插入的最后一行”(并且可能不适用于大多数DML密集型应用程序)。

类似地,遗憾的是,在处理大型数据集时,实现ORDER BY的解决方案可能是灾难性的。 如果我有10亿条记录并想要最后10条记录,那么订购10亿条记录并选择最后10条记录是非常愚蠢的。

这里的问题是,BOTTOM在将它与TOP进行比较时没有我们想到的含义。

当一次又一次地插入,删除,插入,删除记录时,存储中会出现一些间隙,如果可能的话,行将插入行。 但是,当我们选择TOP时,我们经常看到的似乎是排序数据,因为它可能是在表格存在的早期插入的。 如果表没有经历多次删除,则可能看起来是有序的。 (例如,创建日期可能与表创建本身一样早。) 但实际情况是,如果这是一个删除量很大的表,那么TOP N行可能看起来根本不像。

所以 - 这里的底线(双关语意思)是那些要求BOTTOM N记录的人实际上并不知道他们要求的是什么。 或者,至少,他们所要求的以及BOTTOM实际上意味着什么并不是一回事。

所以 - 解决方案可能满足请求者的实际业务需求......但不符合成为BOTTOM的标准。

user9323238 answered 2019-09-09T12:06:47Z
1 votes
SELECT TOP 10*from TABLE1 ORDER BY ID DESC

其中ID是TABLE1的主键。

Er. Binod Mehta answered 2019-09-09T12:07:12Z
0 votes

试试这个。

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
HumbleWebDev answered 2019-09-09T12:07:37Z
0 votes

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

例如,如果要获取记录在表中的所有位置,除了最新的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
Red answered 2019-09-09T12:08:11Z
0 votes

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

SELECT * FROM 
    (SELECT TOP 200 * FROM [table] t2 ORDER BY t2.[column] DESC) t1
    ORDER BY t1.[column]
sheppe answered 2019-09-09T12:08:38Z
0 votes

首先,使用以下表格根据表的原始顺序在子查询中创建索引:

ROW_NUMBER () OVER (ORDER BY (SELECT NULL) ) AS RowIndex

然后按照您在主查询中创建的TOP列来降序表:

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
Thiago Marques answered 2019-09-09T12:09:26Z
translate from https://stackoverflow.com:/questions/1876606/how-to-select-bottom-most-rows