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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16568/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 11:55:56  来源:igfitidea点击:

How to select the nth row in a SQL database table?

mysqlsqldatabaseoraclepostgresql

提问by Charles Roper

I'm interested in learning some (ideally) database agnostic ways of selecting the nth row from a database table. It would also be interesting to see how this can be achieved using the native functionality of the following databases:

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

  • SQL Server
  • MySQL
  • PostgreSQL
  • SQLite
  • Oracle
  • 数据库服务器
  • MySQL
  • PostgreSQL
  • SQLite
  • 甲骨文

I am currently doing something like the following in SQL Server 2005, but I'd be interested in seeing other's more agnostic approaches:

我目前正在 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

Credit for the above SQL: Firoz Ansari's Weblog

上述 SQL 的功劳:Firoz Ansari 的博客

Update:See Troels Arvin's answerregarding the SQL standard. Troels, have you got any links we can cite?

更新:请参阅Troels Arvin关于 SQL 标准的回答Troels,你有任何我们可以引用的链接吗?

采纳答案by Henrik Gustafsson

There are ways of doing this in optional parts of the standard, but a lot of databases support their own way of doing it.

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

A really good site that talks about this and other things is http://troels.arvin.dk/db/rdbms/#select-limit.

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

Basically, PostgreSQL and MySQL supports the non-standard:

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

SELECT...
LIMIT y OFFSET x 

Oracle, DB2 and MSSQL supports the standard windowing functions:

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

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

(which I just copied from the site linked above since I never use those DBs)

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

Update:As of PostgreSQL 8.4 the standard windowing functions are supported, so expect the second example to work for PostgreSQL as well.

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

Update:SQLite added window functions support in version 3.25.0 on 2018-09-15 so both forms also work in SQLite.

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

回答by Neall

PostgreSQL supports windowing functionsas defined by the SQL standard, but they're awkward, so most people use (the non-standard) LIMIT/ OFFSET:

PostgreSQL 支持SQL 标准定义的窗口函数,但它们很笨拙,所以大多数人使用(非标准)LIMIT/OFFSET

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

This example selects the 21st row. OFFSET 20is telling Postgres to skip the first 20 records. If you don't specify an ORDER BYclause, there's no guarantee which record you will get back, which is rarely useful.

本示例选择第 21 行。OFFSET 20告诉 Postgres 跳过前 20 条记录。如果您不指定ORDER BY子句,则无法保证您会返回哪个记录,这很少有用。

回答by Ellen Teapot

I'm not sure about any of the rest, but I know SQLite and MySQL don't have any "default" row ordering. In those two dialects, at least, the following snippet grabs the 15th entry from the_table, sorting by the date/time it was added:

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

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

(of course, you'd need to have an added DATETIME field, and set it to the date/time that entry was added...)

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

回答by Ben Breen

SQL 2005 and above has this feature built-in. Use the ROW_NUMBER() function. It is excellent for web-pages with a << Prev and Next >> style browsing:

SQL 2005 及更高版本内置了此功能。使用 ROW_NUMBER() 函数。它非常适合具有 << Prev and Next >> 样式浏览的网页:

Syntax:

句法:

SELECT
    *
FROM
    (
        SELECT
            ROW_NUMBER () OVER (ORDER BY MyColumnToOrderBy) AS RowNum,
            *
        FROM
            Table_1
    ) sub
WHERE
    RowNum = 23

回答by Tim Saunders

I suspect this is wildly inefficient but is quite a simple approach, which worked on a small dataset that I tried it on.

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

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

This would get the 5th item, change the second top number to get a different nth item

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

SQL server only (I think) but should work on older versions that do not support ROW_NUMBER().

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

回答by Nick Berardi

1 small change: n-1 instead of n.

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

select *
from thetable
limit n-1, 1

回答by Rameshwar Pawale

Verify it on SQL Server:

在 SQL Server 上验证它:

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

This will give you 10th ROW of emp table!

这将为您提供 emp 表的第 10 行!

回答by Troels Arvin

Contrary to what some of the answers claim, the SQL standard is not silent regarding this subject.

与某些答案所声称的相反,SQL 标准并没有就此主题保持沉默。

Since SQL:2003, you have been able to use "window functions" to skip rows and limit result sets.

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

And in SQL:2008, a slightly simpler approach had been added, using
OFFSET skipROWS FETCH FIRST nROWS ONLY

在 SQL:2008 中,添加了一个稍微简单的方法,使用
OFFSET skipROWS FETCH FIRST nROWS ONLY

Personally, I don't think that SQL:2008's addition was really needed, so if I were ISO, I would have kept it out of an already rather large standard.

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

回答by Adam V

When we used to work in MSSQL 2000, we did what we called the "triple-flip":

当我们过去在 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

It wasn't elegant, and it wasn't fast, but it worked.

它不优雅,速度也不快,但确实有效。

回答by Aditya

SQL SERVER

SQL服务器



Select n' th record from top

从顶部选择第 n 条记录

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

select n' th record from bottom

从底部选择第 n 条记录

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