【问题标题】:T-SQL How to select only Second row from a table?T-SQL 如何从表中只选择第二行?
【发布时间】:2010-09-01 10:38:52
【问题描述】:

我有一个表,我需要检索第二行的 ID。如何实现?

Top 2 我选择了前两行,但我只需要第二行

【问题讨论】:

    标签: sql-server tsql


    【解决方案1】:

    在 SQL Server 2012+ 中,您可以使用 OFFSET...FETCH:

    SELECT
       <column(s)>
    FROM
       <table(s)>
    ORDER BY
       <sort column(s)>
    OFFSET 1 ROWS   -- Skip this number of rows
    FETCH NEXT 1 ROWS ONLY;  -- Return this number of rows
    

    【讨论】:

    • 我从未见过 OFFSET 和 FETCH 功能——这太棒了!
    • 注意:需要 ORDER BY 子句存在
    • 为了避免 order by Do - Order by (Select NULL)
    【解决方案2】:

    假设 SQL Server 2005+ 是如何获得 just 第二行的示例(我想您可能会问 - 这就是 top 不适合您的原因?)

    set statistics io on
    
    ;with cte as
    (
      select *
        , ROW_NUMBER() over (order by number) as rn
      from master.dbo.spt_values
    ) 
    select *
    from cte
    where rn = 2
    
    /* Just to add in what I was running RE: Comments */
    ;with cte as
    (
      select top 2 *
        , ROW_NUMBER() over (order by number) as rn
      from master.dbo.spt_values
    ) 
    select *
    from cte
    where rn = 2
    

    【讨论】:

    • 通过在 CTE 中使用 TOP 2,就像我在我的回答中所做的那样(除了 ROW_NUMBER()),您可以将查询效率提高大约 6 倍。使用 @987654326 @我的版本的 TotalSubtreeCost 为 0.0125678,而此版本(不使用 TOP 2)的值为 0.06937763,同时返回相同的结果集。
    • @KM - 我不确定那里是否有真正的节省,而不是帮助使估计的成本更准确。当我使用set statistics io on 时,它看起来并没有任何区别。自从stackoverflow.com/questions/3424650/…
    • 当我使用set statistics io on 运行它时,您的版本在添加TOP 2 后使用Table 'spt_values'. Scan count 1, logical reads 18, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 运行,我得到Table 'spt_values'. Scan count 1, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 另外,set showplan_all on 表明执行计划不同。
    • @KM - 您运行的代码与我编辑的答案中的代码相同吗?我已经在 SQL Server 2008 和 2005 上进行了测试,并且两者都得到了Table 'spt_values'. Scan count 1, logical reads 6, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 那么可能是依赖于服务包的行为?
    • 是的,我正在运行它,就像在您的编辑中一样,第一个版本有:Table 'spt_values'. Scan count 1, logical reads 18, physical reads 1, read-ahead reads 16, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.,第二个版本(TOP 2)有:Table 'spt_values'. Scan count 1, logical reads 6, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.。当我运行select count(*) from master.dbo.spt_values 我得到2346,你得到了什么?如果行数相同,则可能归结为硬件和内存使用情况。
    【解决方案3】:

    如果字段 ID 是唯一的,则不需要行号函数。

    SELECT TOP 1 *
    FROM (
      SELECT TOP 2 * 
      FROM yourTable
      ORDER BY ID
    ) z
    ORDER BY ID DESC
    

    【讨论】:

    • 有人可以帮助解释为什么z 在第二个 ORDER BY 子句之前是必需的吗?
    • @Rennitbaby z 是给封闭子查询的别名,它可以是任何字母或单词.. 省略它会引发语法错误
    【解决方案4】:

    使用ROW_NUMBER() 对行进行编号,但使用TOP 仅处理前两行。

    试试这个:

    DECLARE @YourTable table (YourColumn int)
    INSERT @YourTable VALUES (5)
    INSERT @YourTable VALUES (7)
    INSERT @YourTable VALUES (9)
    INSERT @YourTable VALUES (17)
    INSERT @YourTable VALUES (25)
    
    ;WITH YourCTE AS
    (
      SELECT TOP 2
        *, ROW_NUMBER() OVER(ORDER BY YourColumn) AS RowNumber
      FROM @YourTable
    ) 
    SELECT *
    FROM YourCTE
    WHERE RowNumber=2
    

    输出:

    YourColumn  RowNumber
    ----------- --------------------
    7           2
    
    (1 row(s) affected)
    

    【讨论】:

      【解决方案5】:

      我猜您使用的是 SQL 2005 或更高版本。第2行选择前2行,使用ORDER BY ROW_COUNT DESC,将第2行排列为第一,然后使用TOP 1选择

      SELECT TOP 1 COLUMN1, COLUMN2
      from (
        SELECT TOP 2 COLUMN1, COLUMN2
        FROM Table
      ) ORDER BY ROW_NUMBER DESC 
      

      【讨论】:

      • row_number 来自哪里?
      【解决方案6】:

      您可以使用OFFSETFETCH NEXT

      SELECT id
      FROM tablename
      ORDER BY column
      OFFSET 1 ROWS
      FETCH NEXT 1 ROWS ONLY;
      

      注意:

      OFFSET 只能与 ORDER BY 子句一起使用。它不能用于其 拥有。

      OFFSET 值必须大于或等于零。它不可能是 负数,否则返回错误。

      OFFSET 参数用于标识返回的起点 结果集中的行。基本上,它排除了第一组 记录。

      FETCH 参数用于返回一组行数。拿来 不能单独使用,与OFFSET结合使用。

      【讨论】:

      • 这需要更高。我在没有 cte 的子查询中使用了它,效果很好。
      【解决方案7】:
      with T1 as
      (
        select row_number() over(order by ID) rownum, T2.ID
        from Table2 T2
      )
      select ID
      from T1
      where rownum=2
      

      【讨论】:

        【解决方案8】:

        在 SELECT 中使用 TOP 2 以获得所需的输出行数。 这将按创建数据的顺序返回。如果您有日期选项,您可以按日期订购,并附上TOP n 条款。

        获取前 2 行;

        SELECT TOP 2 [Id] FROM table 
        

        按某个字段获取前 2 行的顺序

        SELECT TOP 2 [ID] FROM table ORDER BY <YourColumn> ASC/DESC
        

        只获取第二行;

        WITH Resulttable AS 
        ( 
          SELECT TOP 2 
            *, ROW_NUMBER() OVER(ORDER BY YourColumn) AS RowNumber 
          FROM @Table 
        )  
        SELECT *
        FROM Resultstable
        WHERE RowNumber = 2
        

        【讨论】:

          【解决方案9】:

          Select top 2 [id] from table Order by [id] desc 应该给你希望你添加的最新两行。

          但是,您必须特别注意 order by 子句,因为它将决定返回的第一行和第二行。

          如果要像这样更改查询:

          Select top 2 [id] from table Order by ModifiedDate desc

          你可以得到两个不同的行。您必须决定在 order by 语句中使用哪一列。

          【讨论】:

            【解决方案10】:

            我有一个比上面那些更简单的方法。

            DECLARE @FirstId int, @SecondId int
            
                SELECT TOP 1 @FirstId = TableId from MyDataTable ORDER BY TableId 
                SELECT TOP 1 @SecondId = TableId from MyDataTable WHERE TableId <> @FirstId  ORDER BY TableId 
            
            SELECT @SecondId 
            

            【讨论】:

            • 上面和下面不是很好的描述,因为顺序取决于票数。此外,如果您能解释您的代码 sn-p 以及您引用的其他答案的优势,那会很酷
            【解决方案11】:

            如果您只是想要 TOP 2,当然 TOP 会出现,但如果您需要单独使用它们以便您可以使用这些值做一些事情,那么请使用 ROW_NUMBER,它可以让您更好地控制要选择的行

            ps。我这样做是因为我不确定 OP 是否在选择中的简单 TOP 2 之后。 (我可能错了!)

            -- Get first row, same as TOP 1
            SELECT [Id] FROM 
            (
                SELECT [Id], ROW_NUMBER() OVER (ORDER BY [Id]) AS Rownumber
                FROM table
            ) results
            WHERE results.Rownumber = 1
            
            -- Get second row only
            SELECT [Id] FROM 
            (
                SELECT [Id], ROW_NUMBER() OVER (ORDER BY [Id]) AS Rownumber
                FROM table
            ) results
            WHERE results.Rownumber = 2
            

            【讨论】:

              【解决方案12】:
              SELECT *
              FROM (
                SELECT top 3 *
                  , ROW_NUMBER() OVER (ORDER BY [newsid] desc) AS Rownumber
                FROM news
                where (news_type in(2,12))
              ) results
              WHERE results.Rownumber = 1
              

              // news 表名和 newsid 列名

              【讨论】:

                【解决方案13】:

                这也很有用:

                SELECT t.*
                FROM (
                  SELECT e1.*
                    , row_number() OVER (ORDER BY e1.Rate DESC) AS _Rank
                  FROM
                  HumanResources.EmployeePayHistory AS e1
                ) AS t
                WHERE t._Rank = 2
                

                【讨论】:

                  【解决方案14】:

                  有一个基于 SQLDiver 和 Taha Ali 的 cmets 的相对简单的解决方案。

                  假设有一个包含由函数 ORIGINAL_LOGIN() 检索到的“域\用户名”的字符串,我不需要域组件。

                  第一种方法

                  DECLARE @Login NVARCHAR(100)
                  SELECT @Login = 'domain\username'
                  -- SELECT @Login = ORIGINAL_LOGIN()
                  
                  SELECT
                      VALUE
                  FROM
                      STRING_SPLIT(@Login, '\')
                  

                  返回一个有 2 行的表。 第一行包含域,第二行包含请求的用户名。

                  使用

                  DECLARE @Login NVARCHAR(100)
                  SELECT @Login = 'domain\username'
                  -- SELECT @Login = ORIGINAL_LOGIN()
                  
                  SELECT
                      VALUE
                  FROM
                      STRING_SPLIT(@Login, '\')
                  ORDER BY
                      (SELECT NULL)
                  OFFSET 1 ROWS
                  FETCH NEXT 1 ROWS ONLY;
                  

                  准确返回临时表的第二行。

                  【讨论】:

                    【解决方案15】:

                    另一个想法是这样的:

                     SELECT MIN(id) FROM
                         (
                          SELECT TOP 2(TAB.[id])
                              FROM TAB 
                              where TAB.field1 =3
                               ORDER BY TAB.[creationDate] DESC
                              ) AS TEST
                         )
                    

                    【讨论】:

                      【解决方案16】:
                      SELECT TOP 2 [Id] FROM table
                      

                      【讨论】:

                      • 您可以对结果进行排序,因此 top 将返回的不是添加的前两个,而是您需要的第一个和第二个
                      • 您必须订购结果,您不能保证您会在没有订购的情况下添加前两个。永远不要使用没有 order by 的 top 并期望得到最早的记录。
                      【解决方案17】:
                      select *
                      from (
                        select ROW_NUMBER() OVER (ORDER BY Column_Name) as ROWNO, *
                        from Table_Name
                      ) Table_Name
                      where ROWNO = 2
                      

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2010-12-21
                        • 2012-09-13
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多