11

我知道:

  • 火鸟:FIRSTSKIP
  • mysql: LIMIT;
  • SQL 服务器:ROW_NUMBER()

有人知道执行结果分页的 SQL ANSI 方式吗?

4

8 回答 8

7

请参阅此页面上的限制 - 带偏移部分:http://troels.arvin.dk/db/rdbms/

顺便说一句,Firebird 从 2.0 版开始也支持 ROWS 子句

于 2009-01-21T14:58:13.703 回答
3

现在有一个标准,不一定是 ANSI 标准(人们给出了很多答案,我认为这是不那么冗长的一个)

SELECT * FROM t1 
WHERE ID > :lastId
ORDER BY ID
FETCH FIRST 3 ROWS ONLY

但并非所有数据库都支持它,下面列出了所有支持的数据库

  • MariaDB:从 5.1 开始支持(通常使用限制/偏移)
  • MySQL:从 3.19.3 开始支持(通常使用限制/偏移)
  • PostgreSQL:从 PostgreSQL 8.4 开始支持(通常使用限制/偏移)
  • SQLite:从 2.1.0 版开始支持
  • Db2 LUW:自版本 7 起受支持
  • Oracle:从 12c 版开始支持(使用带有 row_num 函数的子选择)
  • Microsoft SQL Server:自 2012 年起受支持(传统上使用 top-N)

您当然可以使用偏移样式,尽管您可能会遇到性能问题

SELECT * FROM t1
ORDER BY ID
OFFSET 0 ROWS
FETCH FIRST 3 ROWS ONLY

它有不同的支持

  • MariaDB:从 5.1 开始支持
  • MySQL:从 4.0.6 开始支持
  • PostgreSQL:自 PostgreSQL 6.5 起支持
  • SQLite:从 2.1.0 版开始支持
  • Db2 LUW:自版本 11.1 起受支持
  • Oracle:自版本 12c 起受支持
  • Microsoft SQL Server:自 2012 年起受支持
于 2018-09-11T16:08:08.713 回答
2

没有官方方式,没有。*

通常,您会希望在数据库访问层中有一个抽象函数来处理它;提示您使用的是 MySQL 或 PostgreSQL,它可以在查询中添加“LIMIT”子句,或者在 Oracle 的子查询上添加 rownum 等等。如果它不知道它可以做任何这些,则退回到获取批次并仅返回完整列表的一部分。

*: eta: 现在有,在 ANSI SQL:2003 中。但它不是全球支持的,它经常表现不佳,而且有点痛苦,因为您必须将您的 ORDER 移动/复制到语句中的新位置,这使得自动换行变得更加困难:

SELECT * FROM (
    SELECT thiscol, thatcol, ROW_NUMBER() OVER (ORDER BY mtime DESC, id) AS rownumber
)
WHERE rownumber BETWEEN 10 AND 20 -- care, 1-based index
ORDER BY rownumber;

SQL:2008(以及它的起源地 DB2)中还有“FETCH FIRST n ROWS ONLY”后缀。但是就像 SQL Server 中的 TOP 前缀和 Informix 中类似的语法一样,您无法指定起点,因此您仍然必须获取并丢弃一些行。

于 2009-01-21T02:26:53.567 回答
0

将您的结果插入存储表中,按照您希望的显示方式进行排序,但使用新的 IDENTITY 列。

现在从该表中选择您感兴趣的 ID 范围。

(完成后一定要清理桌子)


或者在客户端上做,因为与演示有关的任何事情通常都不应该在 SQL Server 上做(在我看来)

于 2009-01-21T01:51:07.990 回答
0
ANSI Sql example:
offset=41, fetchsize=10

SELECT TOP(10) *
FROM table1
WHERE table1.ID NOT IN (SELECT TOP(40) table1.ID FROM table1)
于 2010-06-03T12:35:02.533 回答
0

对于分页,我们需要一个RowNo列来过滤它 - 它应该在一个字段上id- 有两个变量,如@PageNo@PageRows。所以我使用这个查询:

SELECT *
FROM (
    SELECT *, (SELECT COUNT(1)
               FROM aTable ti
               WHERE ti.id < t.id) As RowNo
    FROM aTable t) tr
WHERE
    tr.RowNo >= (@PageNo - 1) * @PageRows + 1 
 AND
    tr.RowNo <= @PageNo * @PageRows 
于 2015-05-14T11:41:28.207 回答
0

我知道我对这个问题非常非常晚,但它仍然是这个问题的最佳结果之一。

然而,这个问题缺少的一个回答是,我相信“正确”的 ANSI SQL 分页方法,至少如果你想要最大的可移植性,是根本不使用LIMIT/ OFFSET/FIRST等,而是做类似的事情:

SELECT *
FROM MyTable
WHERE ColumnA > ?
ORDER BY ColumnA ASC

where?是使用支持它们的库的参数(例如PDO在 PHP 中)。

这里的想法很简单,当获取第一页时,我们传递一个匹配每个可能行的参数,例如,如果ColumnA是文本,我们将传递一个空字符串 ( '')。然后我们读入尽可能多的结果,然后发布其余的。这可能意味着在后台获取了一些额外的行,但我们这里的优先级是兼容性。

为了获取下一页,我们ColumnA从结果中的最后一行获取 的值,并将其作为参数传入,这样我们只会获取出现在它之后的值。要在另一个方向运行相同的查询,只需交换>for<ASCfor DESC

这种方法有一些重要的注意事项:

  1. 由于我们使用条件,您的 DBMS 可以自由地使用索引来优化请求,这实际上可以比一些“适当的”分页方法更快,因为您消除行而不是超越它们。
  2. 这种形式的分页比基于行号的方法更紧密地锚定。使用行号偏移时,如果您向表中偏移,但添加的新行排序早于当前页面,则会导致结果移动到后面的页面。例如,如果您当前页面的最后一行是mango,但是自从获取它之后,为appleand添加了行carrot,那么mango现在也可能出现在下一页上,因为它已按排序顺序移动。通过使用这种情况是ColumnA > 'mango'不可能发生的。DATETIME这在您按 a 进行排序且频繁更新的情况下非常有用。
  3. 这个技巧可以在两个方向上起作用,通过在向后(翻转><ASC到)时颠倒提到的排序顺序并从每页结果的第一行而不是最后一行DESC传递值。ColumnA请注意,如果将值添加到您的表中,则可能意味着您的第一页可能会更短,但这是一个相当小的问题。
  4. 为确保您在最后一页(或第一页),您应该获取N + 1行,其中N是您想要每页的行数,这样您可以检测是否还有更多行要获取。
  5. 如果您有一个只有唯一值的列,则此方法效果最佳,但仍然可以在更复杂的情况下使用,只要您可以扩展您的ORDER BY子句(和WHERE条件)以包含足够多的列以使每一行都是唯一的。

所以它不是没有一些问题,但它是迄今为止最兼容的方法,因为每个 SQL 数据库都会支持它。

于 2019-10-23T17:24:36.800 回答
-1

顺便说一句,Troels,PostgreSQL 支持限制/偏移

于 2009-08-29T01:08:17.767 回答