【问题标题】:Selecting Nth Record in an SQL Query在 SQL 查询中选择第 N 条记录
【发布时间】:2009-06-20 20:47:10
【问题描述】:

我有一个正在运行的 SQL 查询,但我只想选择一个特定的行。例如,假设我的查询是:

Select * from Comments

假设这返回 10 行,我只想选择此查询返回的第 8 条记录。我知道我能做到:

Select Top 5 * from Comments

要获取该查询的前 5 条记录,但我只想选择某条记录,我可以在此查询中添加什么来做到这一点(类似于 top)。

谢谢

杰克

【问题讨论】:

  • 您使用的是什么数据库平台? sql2000? sql2005?甲骨文?
  • 我不得不问“为什么是 8th”? 8th 有什么特别的地方可以让使用常规 where 子句更容易选择吗?
  • 8 号没有什么特别之处,这就是我脑海中突然出现的东西。我正在使用 SQL2005

标签: sql sql-server-2005


【解决方案1】:

这是一道经典的面试题。

在 Ms SQL 2005+ 中,您可以使用 ROW_NUMBER() 关键字并使用谓词 ROW_NUMBER = n

USE AdventureWorks;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
    FROM Sales.SalesOrderHeader 
)  

SELECT * 
FROM OrderedOrders 
WHERE RowNumber = 5;

在 SQL2000 中你可以做类似的事情

SELECT Top 1 *FROM
[tblApplications]
where [ApplicationID] In
(
    SELECT TOP 5 [ApplicationID]
    FROM [dbo].[tblApplications]
    order by applicationId Desc
)

【讨论】:

  • 你会说这是正确的做事方式吗? (如果有这样的事情)我在此页面上看到了 3 种不同的方法来实现我的目标,但我想知道这三种方法中是否有任何一种具有任何特殊优势(效率等)
  • 正如其他人所说。为什么你特别需要第8个?在有其他谓词的地方询问 nth 通常是更可取的选择。如果您经常获得第 n 次,是否需要针对性能进行优化。
  • 在这种情况下衡量“最佳”的最佳方法是针对与您的实时数据集的平衡非常匹配的测试数据集测试技术(但如果您的实时数据集较小,最好更大此刻)并查看查询规划器对它们的响应。查看明显的查询计划,看看是否有像全表扫描这样令人讨厌的事情开始出现在其他方法中没有的地方,还观察 SQL 分析器的结果,看看这些技术在 CPU 上是否有很大差异或由于其他原因导致页面读取加载。
  • @John,SQL2K 查询并没有像你想象的那样做。
  • 哎呀,现在已修复但未经测试。我只是抓住了我写的一个查询并更改了它,甚至没有查看结果,在我的辩护中,我充满了酒:O)
【解决方案2】:

怎么样

SELECT TOP 1 * FROM 
   (SELECT TOP 8 * FROM Comments ORDER BY foo ASC)
ORDER BY foo DESC

【讨论】:

  • 适用于 SQL2K。请注意,如果 foo 不是唯一的,则返回哪一行是不确定的。
  • 因为两次选择,效率非常低。
【解决方案3】:

首先,您应该说明您使用的是哪个 RDBMS。

其次,您应该仔细考虑您要完成的工作。关系数据库是基于集合的。通常,集合中元素的顺序无关紧要。你会想问为什么在这种情况下它很重要,然后看看是否有更好的方法将顺序的概念嵌入到查询本身中。

例如,在 SQL Server 2005(和其他 RDBMS)中,您可以使用 ROW_NUMBER 函数根据您指定的条件为返回的每一行分配一个序号。然后,您可以根据行号选择行。来自在线书籍的示例:

USE AdventureWorks;
GO
WITH OrderedOrders AS
(
    SELECT SalesOrderID, OrderDate,
    ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber'
    FROM Sales.SalesOrderHeader 
) 
SELECT * 
FROM OrderedOrders 
WHERE RowNumber BETWEEN 50 AND 60;

【讨论】:

  • John:在内部查询中添加 TOP 子句会改变性能吗?即 SELECT TOP N SalesOrderID, OrderDate, ROW_NUMBER() OVER (ORDER BY OrderDate) AS 'RowNumber' FROM Sales.SalesOrderHeader 其中 N = 行号的最大限制(在这种情况下为 60)你怎么看?
  • 我猜想上面的 cmets 当 N 在被选择的记录数的较低范围内时是有意义的。例如如果我想要 10000 条记录中的 50 到 60 条记录。
  • 我觉得你应该试试看,看看执行计划。 SQL Server 能够注意到外部 SELECT 包括对 CTE 中 ROW_NUMBER 函数值的测试。它很可能不会只选择所有 SalesOrderHeader 行然后才进行过滤。您应该尝试一下并找出答案。
  • 我的机器上没有安装 SQL Server。所以,我不能试一试。对此感到抱歉。
【解决方案4】:
SELECT * FROM comments WHERE ...conditions... LIMIT 1 OFFSET 8

OFFSET 对 MySQL 来说是个好东西

【讨论】:

    【解决方案5】:

    对于 SQL Server 2005:

    select rank() OVER (ORDER BY c.subject, c.date) as rank, c.subject, c.date
       from comments c
       where rank = 8
    

    【讨论】:

    • 由于某种原因,我收到了排名错误:列名“排名”无效。如果我执行所有操作,直到我得到一个看起来我认为它应该包含一个名为 rank 的列的表,有点奇怪,我不能将 where 与语句的其余部分一起使用
    • 这是行不通的——你不能引用排名列,除非你把它放在派生表或 CTE 中——像这样:SELECT * FROM (SELECT rank() OVER (ORDER BY c .subject, c.date) AS rank, c.subject, c.date FROM cmets c) 作为 WHERE a.rank = 8
    【解决方案6】:

    好吧,在 T-SQL(SQL Server 的方言)中,您可以执行以下操作:

    SELECT TOP 1 *
      FROM (SELECT TOP 8 *
              FROM Table
             ORDER
                BY SortField)
     ORDER
        BY SortField DESC
    

    这样你就得到了第 8 条记录。

    【讨论】:

      【解决方案7】:

      我已阅读问题和您的 cmets,您希望接下来 3 个博客 cmets 等。

      您的表格结构如何?
      假设您有博文 Id,并且每篇博文都按升序生成评论 Id,您可以根据当前 Id 进行 SELECT。

      例如如果 blogpostId = 101,您将通过发布的 Id 获得前 3 个 cmets 订单。现在让我们说,您想要获得接下来的 3 个 cmets - 您可以在显示到评论 id 的最后一个评论 id 之间执行 SELECT WHERE commentId - 3

      但这一切都取决于您的表是如何定义的。

      【讨论】:

      • 肯定的。让前端做更多的记账。
      【解决方案8】:

      在没有 ROW_NUMBER() 函数的 SQL 2000 中,您可以使用如下解决方法:

      SELECT CommentsTableFieldList, IDENTITY(INT, 1,1) as seqNo 
      INTO #SeqComments 
      FROM Comments
      
      SELECT * FROM #SeqComments 
      WHERE seqNo = 8
      

      【讨论】:

      • 这不是创建临时表的方法。使用#-前缀,除非您需要创建一个恰好位于 tempdb 中的普通用户表。
      • 笨拙。使用这个:SELECT TOP 1 ... FROM (SELECT TOP 8 ... ORDER BY x ASC) foo ORDER BY x DESC
      • 并非总是有一个列来执行排序及其反向操作。
      • 这样更好:没有应用任何订单
      【解决方案9】:
      select top 1 *
      from TableName
      where ColumnName1 in
      (
          select top nth ColumnName1
          from TableName
          order by ColumnName1 desc
      )
      order by ColumnName1 desc
      

      【讨论】:

        【解决方案10】:

        SELECT reference,使用 LIMIT 关键字:

        SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15
        SELECT * FROM tbl LIMIT 5;     # Retrieve first 5 rows
        

        注意:这是针对 MySQL 的,其他 SQL 引擎可能有不同的关键字。

        【讨论】:

          【解决方案11】:
          Select from tablename limit nthrow,1;
          

          【讨论】:

            【解决方案12】:

            试试这个

            让我们假设,我们要选择 WC_Video 表的第 5 行 还有

            Select * from (Select Row_Number() over (Order by Uploadedon) as 'rownumber',* from Wc_Video )as Temp where rownumber=5
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-06-21
              • 1970-01-01
              • 1970-01-01
              • 2019-02-28
              • 2019-07-15
              • 1970-01-01
              • 1970-01-01
              • 2018-02-07
              相关资源
              最近更新 更多