如何选择最底行?

时间:2009-12-09 20:21:16

标签: sql sql-server database select keyword

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

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

15 个答案:

答案 0 :(得分:91)

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

答案 1 :(得分:79)

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

答案 2 :(得分:31)

抱歉,我认为我认为没有任何正确答案。

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

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

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

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

答案 3 :(得分:14)

从员工中选择底部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
)

答案 4 :(得分:3)

目前接受的答案是" Justin Ethier"如#34; 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

我绝不会声称在所有情况下使用这个都是个好主意,但它可以提供理想的结果。

答案 5 :(得分:2)

您需要做的就是撤消ORDER BY。添加或删除DESC

答案 6 :(得分:1)

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

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;

答案 7 :(得分:1)

“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

感谢。

答案 8 :(得分:1)

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

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

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

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

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

同样,不幸的是,在处理大型数据集时,实现ORDER BY的解决方案可能是灾难性的。如果我拥有10亿条记录并希望获得最后10条记录,那么订购10亿条记录并选择最后10条记录是非常愚蠢的。

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

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

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

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

答案 9 :(得分:1)

SELECT TOP 10*from TABLE1 ORDER BY ID DESC

其中ID是TABLE1的主键。

答案 10 :(得分:0)

试试这个。

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

答案 11 :(得分:0)

我已经提出了一个解决方案,并不需要您知道返回的行数。

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

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

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

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

答案 14 :(得分:0)

您可以使用OFFSET FETCH子句。

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/