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

Cha*_*per 373 mysql sql database oracle postgresql

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

  • SQL Server
  • MySQL的
  • PostgreSQL的
  • SQLite的
  • 神谕

我目前正在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
Run Code Online (Sandbox Code Playgroud)

感谢上述SQL:Firoz Ansari的Weblog

更新:请参阅Troels Arvin关于SQL标准的答案.Troels,您有任何我们能引用的链接吗?

Hen*_*son 330

有很多方法可以在标准的可选部分中执行此操作,但许多数据库都支持自己的方法.

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

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

SELECT...
LIMIT y OFFSET x 
Run Code Online (Sandbox Code Playgroud)

Oracle,DB2和MSSQL支持标准窗口函数:

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

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

更新:从PostgreSQL 8.4开始,支持标准的窗口函数,所以期望第二个例子也适用于PostgreSQL.

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

  • 不应该是`WHERE rownumber = n`才能获得第n行? (5认同)
  • MySQL也使用OFFSET和LIMIT语法.Firebird使用FIRST和SKIP关键字,但它们是在SELECT之后放置的. (2认同)

Nea*_*all 94

PostgreSQL中LIMIT/ OFFSET语法是:

SELECT
    *
FROM
    mytable
ORDER BY
    somefield
LIMIT 1 OFFSET 20;
Run Code Online (Sandbox Code Playgroud)

此示例选择第21行.OFFSET 20告诉Postgres跳过前20条记录.如果您没有指定一个ORDER BY条款,则无法保证您将获得哪条记录,这很少有用.

显然,SQL标准对疯狂窗口函数之外的限制问题保持沉默,这就是每个人以不同方式实现它的原因.


Ell*_*pot 28

我不确定其余的,但我知道SQLite和MySQL没有任何"默认"行排序.在这两种方言中,至少,以下片段从the_table中获取第15个条目,按添加的日期/时间排序:

SELECT * FROM the_table ORDER BY added DESC LIMIT 1,15
Run Code Online (Sandbox Code Playgroud)

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

  • 实际上,从这里 http://php.about.com/od/mysqlcommands/g/Limit_sql.htm,如果你想获取第 15 个条目,你会不会做 LIMIT 14, 1 (0th 是第一个元素,1长度 (2认同)

Ben*_*een 22

SQL 2005及更高版本内置了此功能.使用ROW_NUMBER()函数.它非常适合浏览"上一页和下一页"样式的网页:

句法:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23
Run Code Online (Sandbox Code Playgroud)


Tim*_*ers 17

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

select top 1 field
from table
where field in (select top 5 field from table order by field asc)
order by field desc
Run Code Online (Sandbox Code Playgroud)

这将获得第5项,更改第二个顶部数字以获得不同的第n项

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


Nic*_*rdi 13

1个小变化:n-1而不是n.

select *
from thetable
limit n-1, 1
Run Code Online (Sandbox Code Playgroud)


Ram*_*ale 12

在SQL Server上验证它:

Select top 10 * From emp 
EXCEPT
Select top 9 * From emp
Run Code Online (Sandbox Code Playgroud)

这将给你第10个emp表的行!


Tro*_*vin 11

与某些答案所声称的相反,SQL标准并未对此主题保持沉默.

从SQL:2003开始,您就可以使用"窗口函数"来跳过行并限制结果集.

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

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


Ada*_*m V 7

当我们以前在MSSQL 2000中工作时,我们做了所谓的"三重翻转":

EDITED

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
Run Code Online (Sandbox Code Playgroud)

它并不优雅,并不快,但它确实有效.


Ami*_*hah 7

这里有一个快速解决您困惑的方法。

SELECT * FROM table ORDER BY `id` DESC LIMIT N, 1
Run Code Online (Sandbox Code Playgroud)

这里你可以通过填充N=0得到最后一行,通过N=1填充倒数第二行,通过填充N=3得到倒数第四行等等。

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

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

SELECT DISTINCT (`amount`) 
FROM cart 
ORDER BY CAST( `amount` AS SIGNED ) DESC 
LIMIT 4 , 1
Run Code Online (Sandbox Code Playgroud)

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


Adi*_*tya 6

SQL SERVER


从顶部选择第n条记录

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n
Run Code Online (Sandbox Code Playgroud)

从底部选择第n条记录

SELECT * FROM (
SELECT 
ID, NAME, ROW_NUMBER() OVER(ORDER BY ID DESC) AS ROW
FROM TABLE 
) AS TMP 
WHERE ROW = n
Run Code Online (Sandbox Code Playgroud)


Mar*_*son 5

甲骨文:

select * from (select foo from bar order by foo) where ROWNUM = x
Run Code Online (Sandbox Code Playgroud)

  • `where ROWNUM = x` 仅适用于 Oracle DB 中的 x = 1。即“where ROWNUM = 2”不会返回任何行。 (2认同)

Kau*_*yak 5

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

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

SELECT * 
FROM   sometable
ORDER BY column_name
OFFSET 2 ROWS FETCH NEXT 1 ROWS ONLY;
Run Code Online (Sandbox Code Playgroud)