代码之家  ›  专栏  ›  技术社区  ›  Charles Roper

如何选择SQL数据库表中的第n行?

  •  488
  • Charles Roper  · 技术社区  · 17 年前

    我有兴趣学习一些(理想情况下)与数据库无关的选择方法 n 数据库表中的第1行。看看如何使用以下数据库的本机功能来实现这一点也很有趣:

    • SQL Server
    • MySQL数据库
    • PostgreSQL
    • 数据库
    • 神谕

    我目前正在SQL Server 2005中执行以下操作,但我有兴趣了解其他更不可知的方法:

    WITH Ordered AS (
    SELECT ROW_NUMBER() OVER (ORDER BY OrderID) AS RowNumber, OrderID, OrderDate
    FROM Orders)
    SELECT *
    FROM Ordered
    WHERE RowNumber = 1000000
    

    以上SQL的优点: Firoz Ansari's Weblog

    更新: 看见 Troels Arvin's answer 关于SQL标准。 特罗尔斯,你有我们可以引用的链接吗?

    34 回复  |  直到 6 年前
        1
  •  294
  •   Chris    15 年前

    在标准的可选部分中有一些方法可以做到这一点,但很多数据库都支持自己的方法。

    一个谈论这个和其他事情的好网站是 http://troels.arvin.dk/db/rdbms/#select-limit .

    PostgreSQL和MySQL基本上支持非标准:

    SELECT...
    LIMIT y OFFSET x 
    

    Oracle、DB2和MSSQL支持标准窗口功能:

    SELECT * FROM (
      SELECT
        ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
        columns
      FROM tablename
    ) AS foo
    WHERE rownumber <= n
    

    (我只是从上面链接的网站上复制的,因为我从未使用过这些数据库)

    更新: PostgreSQL 8.4支持标准窗口函数,因此第二个示例也适用于PostgreSQL。

    更新: SQLite在2018年9月15日的3.25.0版本中添加了窗口函数支持,因此这两种形式也适用于SQLite。

        2
  •  85
  •   Faisal    9 年前

    PostgreSQL支持 windowing functions 正如SQL标准所定义的,但它们很笨拙,所以大多数人使用(非标准) LIMIT / OFFSET :

    SELECT
        *
    FROM
        mytable
    ORDER BY
        somefield
    LIMIT 1 OFFSET 20;
    

    此示例选择第21行。 OFFSET 20 告诉Postgres跳过前20条记录。如果不指定 ORDER BY 条款,不能保证你会得到哪条记录,这很少有用。

        3
  •  26
  •   Ellen Teapot    17 年前

    其余的我都不确定,但我知道SQLite和MySQL没有任何“默认”的行顺序。至少在这两种方言中,以下代码段从_table中抓取了第15个条目,按添加日期/时间排序:

    SELECT * 
    FROM the_table 
    ORDER BY added DESC 
    LIMIT 1,15
    

    (当然,您需要添加一个DATETIME字段,并将其设置为添加条目的日期/时间…)

        4
  •  19
  •   Faisal    9 年前

    SQL 2005及更高版本内置了此功能。请使用ROW_NUMBER()函数。它非常适合具有<<上一页和下一页>>样式浏览:

    语法:

    SELECT
        *
    FROM
        (
            SELECT
                ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
                *
            FROM
                Table_1
        ) sub
    WHERE
        RowNum = 23
    
        5
  •  16
  •   Tim    17 年前

    我怀疑这是非常低效的,但这是一种非常简单的方法,它适用于我尝试过的一个小数据集。

    select top 1 field
    from table
    where field in (select top 5 field from table order by field asc)
    order by field desc
    

    这将得到第五个项目,将第二个顶部数字更改为不同的第n个项目

    仅限SQL服务器(我认为),但应该适用于不支持ROW_NUMBER()的旧版本。

        6
  •  12
  •   guitarthrower    11 年前

    在SQL Server上验证它:

    Select top 10 * From emp 
    EXCEPT
    Select top 9 * From emp
    

    这将为你提供第10行emp桌!

        7
  •  11
  •   user1357154 Nick Berardi    13 年前

    与一些答案所声称的相反,SQL标准并没有对这个问题保持沉默。

    自SQL:2003以来,您可以使用“窗口函数”跳过行并限制结果集。

    在SQL:2008中,添加了一种稍微简单的方法,使用
    OFFSET skip ROWS FETCH FIRST n ROWS ONLY

    就我个人而言,我不认为真的需要添加SQL:2008,所以如果我是ISO,我会把它排除在已经相当大的标准之外。

        8
  •  9
  •   Troels Arvin    8 年前

    1个小变化:n-1代替n。

    select *
    from thetable
    limit n-1, 1
    
        9
  •  6
  •   Mark Harrison    17 年前

    SQL服务器


    从顶部选择第n条记录

    SELECT * FROM (
    SELECT 
    ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW
    FROM TABLE 
    ) AS TMP 
    WHERE ROW = n
    

    从底部选择第n条记录

    SELECT * FROM (
    SELECT 
    ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
    FROM TABLE 
    ) AS TMP 
    WHERE ROW = n
    
        10
  •  6
  •   Adam V    14 年前

    当我们使用MSSQL 2000时,我们做了所谓的“三重翻转”:

    编辑

    DECLARE @InnerPageSize int
    DECLARE @OuterPageSize int
    DECLARE @Count int
    
    SELECT @Count = COUNT(<column>) FROM <TABLE>
    SET @InnerPageSize = @PageNum * @PageSize
    SET @OuterPageSize = @Count - ((@PageNum - 1) * @PageSize)
    
    IF (@OuterPageSize < 0)
        SET @OuterPageSize = 0
    ELSE IF (@OuterPageSize > @PageSize)
        SET @OuterPageSize = @PageSize
    
    DECLARE @sql NVARCHAR(8000)
    
    SET @sql = 'SELECT * FROM
    (
        SELECT TOP ' + CAST(@OuterPageSize AS nvarchar(5)) + ' * FROM
        (
            SELECT TOP ' + CAST(@InnerPageSize AS nvarchar(5)) + ' * FROM <TABLE> ORDER BY <column> ASC
        ) AS t1 ORDER BY <column> DESC
    ) AS t2 ORDER BY <column> ASC'
    
    PRINT @sql
    EXECUTE sp_executesql @sql
    

    它不优雅,也不快,但它奏效了。

        11
  •  6
  •   Aditya    12 年前

    这是一个快速解决你困惑的方法。

    SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1
    

    在这里,您可以通过填充N=0得到最后一行,通过N=1得到倒数第二行,通过填充N=3得到倒数第四行,以此类推。

    这是面试中非常常见的问题,这很简单。

    此外,如果你想要金额、ID或一些数字排序顺序,你可以在MySQL中使用CAST函数。

    SELECT DISTINCT (`amount`) 
    FROM cart 
    ORDER BY CAST( `amount` AS SIGNED ) DESC 
    LIMIT 4 , 1
    

    在这里,通过填写N=4,您将能够从CART表中获得最高金额的倒数第五条记录。您可以调整字段和表名并提出解决方案。

        12
  •  4
  •   Amit Shah    14 年前

    在Oracle 12c中,您可以使用 OFFSET..FETCH..ROWS 选项与 ORDER BY

    例如,要获取从顶部开始的第三条记录:

    SELECT * 
    FROM   sometable
    ORDER BY column_name
    OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;
    
        13
  •  2
  •   Andrew G. Johnson    17 年前

    神谕:

    select * from (select foo from bar order by foo) where ROWNUM = x
    
        14
  •  2
  •   Kibbee    17 年前

    添加:

    LIMIT n,1
    

    这将把结果限制为从结果n开始的一个结果。

        15
  •  2
  •   Greg Hurlman    17 年前

    例如,如果你想选择MSSQL中的每10行,你可以使用;

    SELECT * FROM (
      SELECT
        ROW_NUMBER() OVER (ORDER BY ColumnName1 ASC) AS rownumber, ColumnName1, ColumnName2
      FROM TableName
    ) AS foo
    WHERE rownumber % 10 = 0
    

    拿着MOD,把数字10换成你想要的任何数字。

        16
  •  2
  •   John Dyer    17 年前

    对于SQL Server,按行号进行操作的通用方法如下:

    SET ROWCOUNT @row --@row = the row number you wish to work on.
    

    例如:

    set rowcount 20   --sets row to 20th row
    
    select meat, cheese from dbo.sandwich --select columns from table at 20th row
    
    set rowcount 0   --sets rowcount back to all rows
    

    这将返回第20行的信息。之后一定要输入行数0。

        17
  •  2
  •   E-A    14 年前

    这是我最近为Oracle编写的一个支持动态分页/排序的sproc的通用版本-HTH

    -- p_LowerBound = first row # in the returned set; if second page of 10 rows,
    --                this would be 11 (-1 for unbounded/not set)
    -- p_UpperBound = last row # in the returned set; if second page of 10 rows,
    --                this would be 20 (-1 for unbounded/not set)
    
    OPEN o_Cursor FOR
    SELECT * FROM (
    SELECT
        Column1,
        Column2
        rownum AS rn
    FROM
    (
        SELECT
            tbl.Column1,
            tbl.column2
        FROM MyTable tbl
        WHERE
            tbl.Column1 = p_PKParam OR
            tbl.Column1 = -1
        ORDER BY
            DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 1, Column1, 'X'),'X'),
            DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 1, Column1, 'X'),'X') DESC,
            DECODE(p_sortOrder, 'A', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate),
            DECODE(p_sortOrder, 'D', DECODE(p_sortColumn, 2, Column2, sysdate),sysdate) DESC
    ))
    WHERE
        (rn >= p_lowerBound OR p_lowerBound = -1) AND
        (rn <= p_upperBound OR p_upperBound = -1);
    
        18
  •  1
  •   Graeme Perrow    17 年前

    但事实上,这一切难道不是一开始就只是良好数据库设计的客厅技巧吗?我很少需要这样的功能,那是为了一个简单的一次性查询来快速生成报告。对于任何真正的工作,使用这样的技巧都会招致麻烦。如果需要选择特定的行,那么只需有一个具有顺序值的列即可。

        19
  •  1
  •   Eric    17 年前

    没有什么花哨的,没有特殊的功能,以防你像我一样使用Cach。。。

    SELECT TOP 1 * FROM (
      SELECT TOP n * FROM <table>
      ORDER BY ID Desc
    )
    ORDER BY ID ASC
    

    假设您有一个可以信任的ID列或日期戳列。

        20
  •  1
  •   LPL user462990    14 年前

    对于SQL server,下面将返回给定表的第一行。

    declare @rowNumber int = 1;
        select TOP(@rowNumber) * from [dbo].[someTable];
    EXCEPT
        select TOP(@rowNumber - 1) * from [dbo].[someTable];
    

    你可以这样循环这些值:

    WHILE @constVar > 0
    BEGIN
        declare @rowNumber int = @consVar;
           select TOP(@rowNumber) * from [dbo].[someTable];
        EXCEPT
           select TOP(@rowNumber - 1) * from [dbo].[someTable];  
    
           SET @constVar = @constVar - 1;    
    END;
    
        21
  •  1
  •   community wiki 2 revs, 2 users 62% Rahul Sharma    14 年前

    LIMIT n,1在MS SQL Server中不起作用。我认为这是唯一一个不支持这种语法的主要数据库。公平地说,它不是SQL标准的一部分,尽管它得到了如此广泛的支持,以至于它应该得到支持。除了SQL server LIMIT之外,它在所有方面都工作得很好。对于SQL server,我还没有找到一个优雅的解决方案。

        22
  •  1
  •   Faisal    9 年前

    在Sybase SQL Anywhere中:

    SELECT TOP 1 START AT n * from table ORDER BY whatever
    

    不要忘记订单,否则它毫无意义。

        23
  •  1
  •   Kaushik Nayak    8 年前

    T-SQL-从表中选择第N个记录号

    select * from
     (select row_number() over (order by Rand() desc) as Rno,* from TableName) T where T.Rno = RecordNumber
    
    Where  RecordNumber --> Record Number to Select
           TableName --> To be Replaced with your Table Name
    

    例如,要从表Employee中选择第5条记录,您的查询应该是

    select * from
     (select row_number() over (order by Rand() desc) as Rno,* from Employee) T where T.Rno = 5
    
        24
  •  0
  •   Michael Fredrickson    14 年前
    SELECT
        top 1 *
    FROM
        table_name
    WHERE
        column_name IN (
            SELECT
                top N column_name
            FROM
                TABLE
            ORDER BY
                column_name
        )
    ORDER BY
        column_name DESC
    

    我写这个查询是为了找到第N行。 此查询的示例如下

    SELECT
        top 1 *
    FROM
        Employee
    WHERE
        emp_id IN (
            SELECT
                top 7 emp_id
            FROM
                Employee
            ORDER BY
                emp_id
        )
    ORDER BY
        emp_id DESC
    
        25
  •  0
  •   THE JOATMON    10 年前

    我来这里参加聚会有点晚了,但我这样做不需要开窗或使用

    WHERE x IN (...)
    
    SELECT TOP 1
    --select the value needed from t1
    [col2]
    FROM
    (
       SELECT TOP 2 --the Nth row, alter this to taste
       UE2.[col1],
       UE2.[col2],
       UE2.[date],
       UE2.[time],
       UE2.[UID]
       FROM
       [table1] AS UE2
       WHERE
       UE2.[col1] = ID --this is a subquery 
       AND
       UE2.[col2] IS NOT NULL
       ORDER BY
       UE2.[date] DESC, UE2.[time] DESC --sorting by date and time newest first
    ) AS t1
    ORDER BY t1.[date] ASC, t1.[time] ASC --this reverses the order of the sort in t1
    

    它似乎运行得相当快,尽管公平地说,我只有大约500行数据

    这在MSSQL中有效

        26
  •  0
  •   RDKells    9 年前
    SELECT * FROM emp a
    WHERE  n = ( 
        SELECT COUNT( _rowid)
        FROM emp b
        WHERE a. _rowid >= b. _rowid
    );
    
        27
  •  0
  •   Dwipam Katariya    9 年前

    要在SQL表的特定范围内选择第n行到第m行,可以使用 LIMIT 条款与 OFFSET 条款。这个 抵消 子句指定在开始返回结果集之前要跳过的行数,以及 极限 子句指定要返回的最大行数。下面是一个SQL查询的示例,用于选择特定范围内的行:

    SELECT *
    FROM your_table_name
    LIMIT (m - n + 1) OFFSET (n - 1);
    

    更换 your_table_name 使用表的实际名称, n 具有起始行号,以及 m 结束行号在所需范围内。请注意,偏移值为 (n - 1) 因为行索引为零,限制值为 (m - n + 1) 以检索该范围内所需的行数。

    例如,如果要从表中选择第3到第7行,可以替换 (n-1) 具有 (3 - 1) (m-n+1) 具有 (7 - 3 + 1) 。这将导致 OFFSET 2 LIMIT 5 。此查询将从表中检索指定范围内的行。

    请确保在支持SQL的数据库管理系统或工具中执行此SQL查询。

        28
  •  0
  •   John Deighan    8 年前

    令人难以置信的是,你能找到一个执行这个的SQL引擎。..

    WITH sentence AS
    (SELECT 
        stuff,
        row = ROW_NUMBER() OVER (ORDER BY Id)
    FROM 
        SentenceType
        )
    SELECT
        sen.stuff
    FROM sentence sen
    WHERE sen.row = (ABS(CHECKSUM(NEWID())) % 100) + 1
    
        29
  •  0
  •   nPcomp    8 年前
    select * from 
    (select * from ordered order by order_id limit 100) x order by 
    x.order_id desc limit 1;
    

    首先按升序排列选择前100行,然后按降序排列选择最后一行,限制为1。然而,这是一个非常昂贵的声明,因为它访问数据两次。